github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/private_data_tutorial.rst (about)

     1  Using Private Data in Fabric
     2  ============================
     3  
     4  This tutorial will demonstrate the use of collections to provide storage
     5  and retrieval of private data on the blockchain network for authorized peers
     6  of organizations.
     7  
     8  The information in this tutorial assumes knowledge of private data
     9  stores and their use cases. For more information, check out :doc:`private-data/private-data`.
    10  
    11  .. note:: These instructions use the new Fabric chaincode lifecycle introduced
    12            in the Fabric v2.0 release. If you would like to use the previous
    13            lifecycle model to use private data with chaincode, visit the v1.4
    14            version of the `Using Private Data in Fabric tutorial <https://hyperledger-fabric.readthedocs.io/en/release-1.4/private_data_tutorial.html>`__.
    15  
    16  The tutorial will take you through the following steps to practice defining,
    17  configuring and using private data with Fabric:
    18  
    19  #. :ref:`pd-build-json`
    20  #. :ref:`pd-read-write-private-data`
    21  #. :ref:`pd-install-define_cc`
    22  #. :ref:`pd-store-private-data`
    23  #. :ref:`pd-query-authorized`
    24  #. :ref:`pd-query-unauthorized`
    25  #. :ref:`pd-purge`
    26  #. :ref:`pd-indexes`
    27  #. :ref:`pd-ref-material`
    28  
    29  This tutorial will deploy the `marbles private data sample <https://github.com/hyperledger/fabric-samples/tree/master/chaincode/marbles02_private>`__
    30  to the Fabric test network to demonstrate how to create, deploy, and use a collection of
    31  private data. You should have completed the task :doc:`install`.
    32  
    33  .. _pd-build-json:
    34  
    35  Build a collection definition JSON file
    36  ------------------------------------------
    37  
    38  The first step in privatizing data on a channel is to build a collection
    39  definition which defines access to the private data.
    40  
    41  The collection definition describes who can persist data, how many peers the
    42  data is distributed to, how many peers are required to disseminate the private
    43  data, and how long the private data is persisted in the private database. Later,
    44  we will demonstrate how chaincode APIs ``PutPrivateData`` and ``GetPrivateData``
    45  are used to map the collection to the private data being secured.
    46  
    47  A collection definition is composed of the following properties:
    48  
    49  .. _blockToLive:
    50  
    51  - ``name``: Name of the collection.
    52  
    53  - ``policy``: Defines the organization peers allowed to persist the collection data.
    54  
    55  - ``requiredPeerCount``: Number of peers required to disseminate the private data as
    56    a condition of the endorsement of the chaincode
    57  
    58  - ``maxPeerCount``: For data redundancy purposes, the number of other peers
    59    that the current endorsing peer will attempt to distribute the data to.
    60    If an endorsing peer goes down, these other peers are available at commit time
    61    if there are requests to pull the private data.
    62  
    63  - ``blockToLive``: For very sensitive information such as pricing or personal information,
    64    this value represents how long the data should live on the private database in terms
    65    of blocks. The data will live for this specified number of blocks on the private database
    66    and after that it will get purged, making this data obsolete from the network.
    67    To keep private data indefinitely, that is, to never purge private data, set
    68    the ``blockToLive`` property to ``0``.
    69  
    70  - ``memberOnlyRead``: a value of ``true`` indicates that peers automatically
    71    enforce that only clients belonging to one of the collection member organizations
    72    are allowed read access to private data.
    73  
    74  To illustrate usage of private data, the marbles private data example contains
    75  two private data collection definitions: ``collectionMarbles``
    76  and ``collectionMarblePrivateDetails``. The ``policy`` property in the
    77  ``collectionMarbles`` definition allows all members of  the channel (Org1 and
    78  Org2) to have the private data in a private database. The
    79  ``collectionMarblesPrivateDetails`` collection allows only members of Org1 to
    80  have the private data in their private database.
    81  
    82  For more information on building a policy definition refer to the :doc:`endorsement-policies`
    83  topic.
    84  
    85  .. code:: json
    86  
    87   // collections_config.json
    88  
    89   [
    90     {
    91          "name": "collectionMarbles",
    92          "policy": "OR('Org1MSP.member', 'Org2MSP.member')",
    93          "requiredPeerCount": 0,
    94          "maxPeerCount": 3,
    95          "blockToLive":1000000,
    96          "memberOnlyRead": true
    97     },
    98  
    99     {
   100          "name": "collectionMarblePrivateDetails",
   101          "policy": "OR('Org1MSP.member')",
   102          "requiredPeerCount": 0,
   103          "maxPeerCount": 3,
   104          "blockToLive":3,
   105          "memberOnlyRead": true
   106     }
   107   ]
   108  
   109  The data to be secured by these policies is mapped in chaincode and will be
   110  shown later in the tutorial.
   111  
   112  This collection definition file is deployed when the chaincode definition is
   113  committed to the channel using the `peer lifecycle chaincode commit command <commands/peerlifecycle.html#peer-lifecycle-chaincode-commit>`__.
   114  More details on this process are provided in Section 3 below.
   115  
   116  .. _pd-read-write-private-data:
   117  
   118  Read and Write private data using chaincode APIs
   119  ------------------------------------------------
   120  
   121  The next step in understanding how to privatize data on a channel is to build
   122  the data definition in the chaincode. The marbles private data sample divides
   123  the private data into two separate data definitions according to how the data will
   124  be accessed.
   125  
   126  .. code-block:: GO
   127  
   128   // Peers in Org1 and Org2 will have this private data in a side database
   129   type marble struct {
   130     ObjectType string `json:"docType"`
   131     Name       string `json:"name"`
   132     Color      string `json:"color"`
   133     Size       int    `json:"size"`
   134     Owner      string `json:"owner"`
   135   }
   136  
   137   // Only peers in Org1 will have this private data in a side database
   138   type marblePrivateDetails struct {
   139     ObjectType string `json:"docType"`
   140     Name       string `json:"name"`
   141     Price      int    `json:"price"`
   142   }
   143  
   144  Specifically access to the private data will be restricted as follows:
   145  
   146  - ``name, color, size, and owner`` will be visible to all members of the channel (Org1 and Org2)
   147  - ``price`` only visible to members of Org1
   148  
   149  Thus two different sets of private data are defined in the marbles private data
   150  sample. The mapping of this data to the collection policy which restricts its
   151  access is controlled by chaincode APIs. Specifically, reading and writing
   152  private data using a collection definition is performed by calling ``GetPrivateData()``
   153  and ``PutPrivateData()``, which can be found `here <https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#ChaincodeStub>`_.
   154  
   155  The following diagram illustrates the private data model used by the marbles
   156  private data sample.
   157  
   158  .. image:: images/SideDB-org1-org2.png
   159  
   160  
   161  Reading collection data
   162  ~~~~~~~~~~~~~~~~~~~~~~~~
   163  
   164  Use the chaincode API ``GetPrivateData()`` to query private data in the
   165  database.  ``GetPrivateData()`` takes two arguments, the **collection name**
   166  and the data key. Recall the collection  ``collectionMarbles`` allows members of
   167  Org1 and Org2 to have the private data in a side database, and the collection
   168  ``collectionMarblePrivateDetails`` allows only members of Org1 to have the
   169  private data in a side database. For implementation details refer to the
   170  following two `marbles private data functions <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02_private/go/marbles_chaincode_private.go>`__:
   171  
   172   * **readMarble** for querying the values of the ``name, color, size and owner`` attributes
   173   * **readMarblePrivateDetails** for querying the values of the ``price`` attribute
   174  
   175  When we issue the database queries using the peer commands later in this tutorial,
   176  we will call these two functions.
   177  
   178  Writing private data
   179  ~~~~~~~~~~~~~~~~~~~~
   180  
   181  Use the chaincode API ``PutPrivateData()`` to store the private data
   182  into the private database. The API also requires the name of the collection.
   183  Since the marbles private data sample includes two different collections, it is called
   184  twice in the chaincode:
   185  
   186  1. Write the private data ``name, color, size and owner`` using the
   187     collection named ``collectionMarbles``.
   188  2. Write the private data ``price`` using the collection named
   189     ``collectionMarblePrivateDetails``.
   190  
   191  For example, in the following snippet of the ``initMarble`` function,
   192  ``PutPrivateData()`` is called twice, once for each set of private data.
   193  
   194  .. code-block:: GO
   195  
   196    // ==== Create marble object, marshal to JSON, and save to state ====
   197  	marble := &marble{
   198  		ObjectType: "marble",
   199  		Name:       marbleInput.Name,
   200  		Color:      marbleInput.Color,
   201  		Size:       marbleInput.Size,
   202  		Owner:      marbleInput.Owner,
   203  	}
   204  	marbleJSONasBytes, err := json.Marshal(marble)
   205  	if err != nil {
   206  		return shim.Error(err.Error())
   207  	}
   208  
   209  	// === Save marble to state ===
   210  	err = stub.PutPrivateData("collectionMarbles", marbleInput.Name, marbleJSONasBytes)
   211  	if err != nil {
   212  		return shim.Error(err.Error())
   213  	}
   214  
   215  	// ==== Create marble private details object with price, marshal to JSON, and save to state ====
   216  	marblePrivateDetails := &marblePrivateDetails{
   217  		ObjectType: "marblePrivateDetails",
   218  		Name:       marbleInput.Name,
   219  		Price:      marbleInput.Price,
   220  	}
   221  	marblePrivateDetailsBytes, err := json.Marshal(marblePrivateDetails)
   222  	if err != nil {
   223  		return shim.Error(err.Error())
   224  	}
   225  	err = stub.PutPrivateData("collectionMarblePrivateDetails", marbleInput.Name, marblePrivateDetailsBytes)
   226  	if err != nil {
   227  		return shim.Error(err.Error())
   228  	}
   229  
   230  
   231  To summarize, the policy definition above for our ``collection.json``
   232  allows all peers in Org1 and Org2 to store and transact
   233  with the marbles private data ``name, color, size, owner`` in their
   234  private database. But only peers in Org1 can store and transact with
   235  the ``price`` private data in its private database.
   236  
   237  As an additional data privacy benefit, since a collection is being used,
   238  only the private data hashes go through orderer, not the private data itself,
   239  keeping private data confidential from orderer.
   240  
   241  Start the network
   242  -----------------
   243  
   244  Now we are ready to step through some commands which demonstrate how to use
   245  private data.
   246  
   247  :guilabel:`Try it yourself`
   248  
   249  Before installing, defining, and using the marbles private data chaincode below,
   250  we need to start the Fabric test network. For the sake of this tutorial, we want
   251  to operate from a known initial state. The following command will kill any active
   252  or stale Docker containers and remove previously generated artifacts.
   253  Therefore let's run the following command to clean up any previous
   254  environments:
   255  
   256  .. code:: bash
   257  
   258     cd fabric-samples/test-network
   259     ./network.sh down
   260  
   261  If you have not run through the tutorial before, you will need to vendor the
   262  chaincode dependencies before we can deploy it to the network. Run the
   263  following commands:
   264  
   265  .. code:: bash
   266  
   267      cd ../chaincode/marbles02_private/go
   268      GO111MODULE=on go mod vendor
   269      cd ../../../test-network
   270  
   271  
   272  If you've already run through this tutorial, you'll also want to delete the
   273  underlying Docker containers for the marbles private data chaincode. Let's run
   274  the following commands to clean up previous environments:
   275  
   276  .. code:: bash
   277  
   278     docker rm -f $(docker ps -a | awk '($2 ~ /dev-peer.*.marblesp.*/) {print $1}')
   279     docker rmi -f $(docker images | awk '($1 ~ /dev-peer.*.marblesp.*/) {print $3}')
   280  
   281  From the ``test-network`` directory, you can use the following command to start
   282  up the Fabric test network with CouchDB:
   283  
   284  .. code:: bash
   285  
   286     ./network.sh up createChannel -s couchdb
   287  
   288  This command will deploy a Fabric network consisting of a single channel named
   289  ``mychannel`` with two organizations (each maintaining one peer node) and an
   290  ordering service while using CouchDB as the state database. Either LevelDB or
   291  CouchDB may be used with collections. CouchDB was chosen to demonstrate how to
   292  use indexes with private data.
   293  
   294  .. note:: For collections to work, it is important to have cross organizational
   295             gossip configured correctly. Refer to our documentation on :doc:`gossip`,
   296             paying particular attention to the section on "anchor peers". Our tutorial
   297             does not focus on gossip given it is already configured in the test network,
   298             but when configuring a channel, the gossip anchors peers are critical to
   299             configure for collections to work properly.
   300  
   301  .. _pd-install-define_cc:
   302  
   303  Install and define a chaincode with a collection
   304  -------------------------------------------------
   305  
   306  Client applications interact with the blockchain ledger through chaincode.
   307  Therefore we need to install a chaincode on every peer that will execute and
   308  endorse our transactions. However, before we can interact with our chaincode,
   309  the members of the channel need to agree on a chaincode definition that
   310  establishes chaincode governance, including the private data collection
   311  configuration. We are going to package, install, and then define the chaincode
   312  on the channel using :doc:`commands/peerlifecycle`.
   313  
   314  The chaincode needs to be packaged before it can be installed on our peers.
   315  We can use the `peer lifecycle chaincode package <commands/peerlifecycle.html#peer-lifecycle-chaincode-package>`__ command
   316  to package the marbles chaincode.
   317  
   318  The test network includes two organizations, Org1 and Org2, with one peer each.
   319  Therefore, the chaincode package has to be installed on two peers:
   320  
   321  - peer0.org1.example.com
   322  - peer0.org2.example.com
   323  
   324  After the chaincode is packaged, we can use the `peer lifecycle chaincode install <commands/peerlifecycle.html#peer-lifecycle-chaincode-install>`__
   325  command to install the Marbles chaincode on each peer.
   326  
   327  :guilabel:`Try it yourself`
   328  
   329  Assuming you have started the test network, copy and paste the following
   330  environment variables in your CLI to interact with the network and operate as
   331  the Org1 admin. Make sure that you are in the `test-network` directory.
   332  
   333  .. code:: bash
   334  
   335      export PATH=${PWD}/../bin:${PWD}:$PATH
   336      export FABRIC_CFG_PATH=$PWD/../config/
   337      export CORE_PEER_TLS_ENABLED=true
   338      export CORE_PEER_LOCALMSPID="Org1MSP"
   339      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   340      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   341      export CORE_PEER_ADDRESS=localhost:7051
   342  
   343  1. Use the following command to package the marbles private data chaincode.
   344  
   345  .. code:: bash
   346  
   347      peer lifecycle chaincode package marblesp.tar.gz --path ../chaincode/marbles02_private/go/ --lang golang --label marblespv1
   348  
   349  This command will create a chaincode package named marblesp.tar.gz.
   350  
   351  2. Use the following command to install the chaincode package onto the peer
   352  ``peer0.org1.example.com``.
   353  
   354  .. code:: bash
   355  
   356      peer lifecycle chaincode install marblesp.tar.gz
   357  
   358  A successful install command will return the chaincode identifier, similar to
   359  the response below:
   360  
   361  .. code:: bash
   362  
   363      2019-04-22 19:09:04.336 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nKmarblespv1:57f5353b2568b79cb5384b5a8458519a47186efc4fcadb98280f5eae6d59c1cd\022\nmarblespv1" >
   364      2019-04-22 19:09:04.336 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marblespv1:57f5353b2568b79cb5384b5a8458519a47186efc4fcadb98280f5eae6d59c1cd
   365  
   366  3. Now use the CLI as the Org2 admin. Copy and paste the following block of
   367  commands as a group and run them all at once:
   368  
   369  .. code:: bash
   370  
   371      export CORE_PEER_LOCALMSPID="Org2MSP"
   372      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
   373      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
   374      export CORE_PEER_ADDRESS=localhost:9051
   375  
   376  4. Run the following command to install the chaincode on the Org2 peer:
   377  
   378  .. code:: bash
   379  
   380      peer lifecycle chaincode install marblesp.tar.gz
   381  
   382  
   383  Approve the chaincode definition
   384  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   385  
   386  Each channel member that wants to use the chaincode needs to approve a chaincode
   387  definition for their organization. Since both organizations are going to use the
   388  chaincode in this tutorial, we need to approve the chaincode definition for both
   389  Org1 and Org2 using the `peer lifecycle chaincode approveformyorg <commands/peerlifecycle.html#peer-lifecycle-chaincode-approveformyorg>`__
   390  command. The chaincode definition also includes the private data collection
   391  definition that accompanies the ``marbles02_private`` sample. We will provide
   392  the path to the collections JSON file using the ``--collections-config`` flag.
   393  
   394  :guilabel:`Try it yourself`
   395  
   396  Run the following commands from the ``test-network`` directory to approve a
   397  definition for Org1 and Org2.
   398  
   399  1. Use the following command to query your peer for the package ID of the
   400  installed chaincode.
   401  
   402  .. code:: bash
   403  
   404      peer lifecycle chaincode queryinstalled
   405  
   406  The command will return the same package identifier as the install command.
   407  You should see output similar to the following:
   408  
   409  .. code:: bash
   410  
   411      Installed chaincodes on peer:
   412      Package ID: marblespv1:f8c8e06bfc27771028c4bbc3564341887881e29b92a844c66c30bac0ff83966e, Label: marblespv1
   413  
   414  2. Declare the package ID as an environment variable. Paste the package ID of
   415  marblespv1 returned by the ``peer lifecycle chaincode queryinstalled`` into
   416  the command below. The package ID may not be the same for all users, so you
   417  need to complete this step using the package ID returned from your console.
   418  
   419  .. code:: bash
   420  
   421      export CC_PACKAGE_ID=marblespv1:f8c8e06bfc27771028c4bbc3564341887881e29b92a844c66c30bac0ff83966e
   422  
   423  3. Make sure we are running the CLI as Org1. Copy and paste the following block
   424  of commands as a group into the peer container and run them all at once:
   425  
   426  .. code :: bash
   427  
   428      export CORE_PEER_LOCALMSPID="Org1MSP"
   429      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   430      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   431      export CORE_PEER_ADDRESS=localhost:7051
   432  
   433  4. Use the following command to approve a definition of the marbles private data
   434  chaincode for Org1. This command includes a path to the collection definition
   435  file.
   436  
   437  .. code:: bash
   438  
   439      export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
   440      peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile $ORDERER_CA
   441  
   442  When the command completes successfully you should see something similar to:
   443  
   444  .. code:: bash
   445  
   446      2020-01-03 17:26:55.022 EST [chaincodeCmd] ClientWait -> INFO 001 txid [06c9e86ca68422661e09c15b8e6c23004710ea280efda4bf54d501e655bafa9b] committed with status (VALID) at
   447  
   448  5. Now use the CLI to switch to Org2. Copy and paste the following block of commands
   449  as a group into the peer container and run them all at once.
   450  
   451  .. code:: bash
   452  
   453      export CORE_PEER_LOCALMSPID="Org2MSP"
   454      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
   455      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
   456      export CORE_PEER_ADDRESS=localhost:9051
   457  
   458  6. You can now approve the chaincode definition for Org2:
   459  
   460  .. code:: bash
   461  
   462      peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --collections-config ../chaincode/marbles02_private/collections_config.json --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile $ORDERER_CA
   463  
   464  Commit the chaincode definition
   465  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   466  
   467  Once a sufficient number of organizations (in this case, a majority) have
   468  approved a chaincode definition, one organization can commit the definition to
   469  the channel.
   470  
   471  Use the `peer lifecycle chaincode commit <commands/peerlifecycle.html#peer-lifecycle-chaincode-commit>`__
   472  command to commit the chaincode definition. This command will also deploy the
   473  collection definition to the channel.
   474  
   475  We are ready to use the chaincode after the chaincode definition has been
   476  committed to the channel. Because the marbles private data chaincode contains an
   477  initiation function, we need to use the `peer chaincode invoke <commands/peerchaincode.html?%20chaincode%20instantiate#peer-chaincode-instantiate>`__ command
   478  to invoke ``Init()`` before we can use other functions in the chaincode.
   479  
   480  :guilabel:`Try it yourself`
   481  
   482  1. Run the following commands to commit the definition of the marbles private
   483  data chaincode to the channel ``mychannel``.
   484  
   485  .. code:: bash
   486  
   487      export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
   488      export ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   489      export ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
   490      peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --version 1.0 --sequence 1 --collections-config ../chaincode/marbles02_private/collections_config.json --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $ORG2_CA
   491  
   492  
   493  When the commit transaction completes successfully you should see something
   494  similar to:
   495  
   496  .. code:: bash
   497  
   498      2020-01-06 16:24:46.104 EST [chaincodeCmd] ClientWait -> INFO 001 txid [4a0d0f5da43eb64f7cbfd72ea8a8df18c328fb250cb346077d91166d86d62d46] committed with status (VALID) at localhost:9051
   499      2020-01-06 16:24:46.184 EST [chaincodeCmd] ClientWait -> INFO 002 txid [4a0d0f5da43eb64f7cbfd72ea8a8df18c328fb250cb346077d91166d86d62d46] committed with status (VALID) at localhost:7051
   500  
   501  2. Use the following command to invoke the ``Init`` function to initialize the
   502  chaincode:
   503  
   504  .. code:: bash
   505  
   506      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marblesp --isInit --tls true --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA -c '{"Args":["Init"]}'
   507  
   508  .. _pd-store-private-data:
   509  
   510  Store private data
   511  ------------------
   512  
   513  Acting as a member of Org1, who is authorized to transact with all of the private data
   514  in the marbles private data sample, switch back to an Org1 peer and
   515  submit a request to add a marble:
   516  
   517  :guilabel:`Try it yourself`
   518  
   519  Copy and paste the following set of commands into your CLI in the `test-network`
   520  directory:
   521  
   522  .. code :: bash
   523  
   524      export CORE_PEER_LOCALMSPID="Org1MSP"
   525      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   526      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   527      export CORE_PEER_ADDRESS=localhost:7051
   528  
   529  Invoke the marbles ``initMarble`` function which
   530  creates a marble with private data ---  name ``marble1`` owned by ``tom`` with a color
   531  ``blue``, size ``35`` and price of ``99``. Recall that private data **price**
   532  will be stored separately from the private data **name, owner, color, size**.
   533  For this reason, the ``initMarble`` function calls the ``PutPrivateData()`` API
   534  twice to persist the private data, once for each collection. Also note that
   535  the private data is passed using the ``--transient`` flag. Inputs passed
   536  as transient data will not be persisted in the transaction in order to keep
   537  the data private. Transient data is passed as binary data and therefore when
   538  using CLI it must be base64 encoded. We use an environment variable
   539  to capture the base64 encoded value, and use ``tr`` command to strip off the
   540  problematic newline characters that linux base64 command adds.
   541  
   542  .. code:: bash
   543  
   544      export MARBLE=$(echo -n "{\"name\":\"marble1\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
   545      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
   546  
   547  You should see results similar to:
   548  
   549  .. code:: bash
   550  
   551      [chaincodeCmd] chaincodeInvokeOrQuery->INFO 001 Chaincode invoke successful. result: status:200
   552  
   553  .. _pd-query-authorized:
   554  
   555  Query the private data as an authorized peer
   556  --------------------------------------------
   557  
   558  Our collection definition allows all members of Org1 and Org2
   559  to have the ``name, color, size, owner`` private data in their side database,
   560  but only peers in Org1 can have the ``price`` private data in their side
   561  database. As an authorized peer in Org1, we will query both sets of private data.
   562  
   563  The first ``query`` command calls the ``readMarble`` function which passes
   564  ``collectionMarbles`` as an argument.
   565  
   566  .. code-block:: GO
   567  
   568     // ===============================================
   569     // readMarble - read a marble from chaincode state
   570     // ===============================================
   571  
   572     func (t *SimpleChaincode) readMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   573     	var name, jsonResp string
   574     	var err error
   575     	if len(args) != 1 {
   576     		return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
   577     	}
   578  
   579     	name = args[0]
   580     	valAsbytes, err := stub.GetPrivateData("collectionMarbles", name) //get the marble from chaincode state
   581  
   582     	if err != nil {
   583     		jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
   584     		return shim.Error(jsonResp)
   585     	} else if valAsbytes == nil {
   586     		jsonResp = "{\"Error\":\"Marble does not exist: " + name + "\"}"
   587     		return shim.Error(jsonResp)
   588     	}
   589  
   590     	return shim.Success(valAsbytes)
   591     }
   592  
   593  The second ``query`` command calls the ``readMarblePrivateDetails``
   594  function which passes ``collectionMarblePrivateDetails`` as an argument.
   595  
   596  .. code-block:: GO
   597  
   598     // ===============================================
   599     // readMarblePrivateDetails - read a marble private details from chaincode state
   600     // ===============================================
   601  
   602     func (t *SimpleChaincode) readMarblePrivateDetails(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   603     	var name, jsonResp string
   604     	var err error
   605  
   606     	if len(args) != 1 {
   607     		return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
   608     	}
   609  
   610     	name = args[0]
   611     	valAsbytes, err := stub.GetPrivateData("collectionMarblePrivateDetails", name) //get the marble private details from chaincode state
   612  
   613     	if err != nil {
   614     		jsonResp = "{\"Error\":\"Failed to get private details for " + name + ": " + err.Error() + "\"}"
   615     		return shim.Error(jsonResp)
   616     	} else if valAsbytes == nil {
   617     		jsonResp = "{\"Error\":\"Marble private details does not exist: " + name + "\"}"
   618     		return shim.Error(jsonResp)
   619     	}
   620     	return shim.Success(valAsbytes)
   621     }
   622  
   623  Now :guilabel:`Try it yourself`
   624  
   625  Query for the ``name, color, size and owner`` private data of ``marble1`` as a member of Org1.
   626  Note that since queries do not get recorded on the ledger, there is no need to pass
   627  the marble name as a transient input.
   628  
   629  .. code:: bash
   630  
   631      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarble","marble1"]}'
   632  
   633  You should see the following result:
   634  
   635  .. code:: bash
   636  
   637      {"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}
   638  
   639  Query for the ``price`` private data of ``marble1`` as a member of Org1.
   640  
   641  .. code:: bash
   642  
   643      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   644  
   645  You should see the following result:
   646  
   647  .. code:: bash
   648  
   649      {"docType":"marblePrivateDetails","name":"marble1","price":99}
   650  
   651  .. _pd-query-unauthorized:
   652  
   653  Query the private data as an unauthorized peer
   654  ----------------------------------------------
   655  
   656  Now we will switch to a member of Org2. Org2 has the marbles private data
   657  ``name, color, size, owner`` in its side database, but does not store the
   658  marbles ``price`` data. We will query for both sets of private data.
   659  
   660  Switch to a peer in Org2
   661  ~~~~~~~~~~~~~~~~~~~~~~~~
   662  
   663  Run the following commands to operate as the Org2 admin and query the Org2 peer.
   664  
   665  :guilabel:`Try it yourself`
   666  
   667  .. code:: bash
   668  
   669      export CORE_PEER_LOCALMSPID="Org2MSP"
   670      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
   671      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
   672      export CORE_PEER_ADDRESS=localhost:9051
   673  
   674  Query private data Org2 is authorized to
   675  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   676  
   677  Peers in Org2 should have the first set of marbles private data (``name,
   678  color, size and owner``) in their side database and can access it using the
   679  ``readMarble()`` function which is called with the ``collectionMarbles``
   680  argument.
   681  
   682  :guilabel:`Try it yourself`
   683  
   684  .. code:: bash
   685  
   686      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarble","marble1"]}'
   687  
   688  You should see something similar to the following result:
   689  
   690  .. code:: json
   691  
   692      {"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}
   693  
   694  Query private data Org2 is not authorized to
   695  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   696  
   697  Peers in Org2 do not have the marbles ``price`` private data in their side database.
   698  When they try to query for this data, they get back a hash of the key matching
   699  the public state but will not have the private state.
   700  
   701  :guilabel:`Try it yourself`
   702  
   703  .. code:: bash
   704  
   705      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   706  
   707  You should see a result similar to:
   708  
   709  .. code:: json
   710  
   711      Error: endorsement failure during query. response: status:500
   712      message:"{\"Error\":\"Failed to get private details for marble1:
   713      GET_STATE failed: transaction ID: d9c437d862de66755076aeebe79e7727791981606ae1cb685642c93f102b03e5:
   714      tx creator does not have read access permission on privatedata in chaincodeName:marblesp collectionName: collectionMarblePrivateDetails\"}"
   715  
   716  Members of Org2 will only be able to see the public hash of the private data.
   717  
   718  .. _pd-purge:
   719  
   720  Purge Private Data
   721  ------------------
   722  
   723  For use cases where private data only needs to be on the ledger until it can be
   724  replicated into an off-chain database, it is possible to "purge" the data after
   725  a certain set number of blocks, leaving behind only hash of the data that serves
   726  as immutable evidence of the transaction.
   727  
   728  There may be private data including personal or confidential
   729  information, such as the pricing data in our example, that the transacting
   730  parties don't want disclosed to other organizations on the channel. Thus, it
   731  has a limited lifespan, and can be purged after existing unchanged on the
   732  blockchain for a designated number of blocks using the ``blockToLive`` property
   733  in the collection definition.
   734  
   735  Our ``collectionMarblePrivateDetails`` definition has a ``blockToLive``
   736  property value of three meaning this data will live on the side database for
   737  three blocks and then after that it will get purged. Tying all of the pieces
   738  together, recall this collection definition  ``collectionMarblePrivateDetails``
   739  is associated with the ``price`` private data in the  ``initMarble()`` function
   740  when it calls the ``PutPrivateData()`` API and passes the
   741  ``collectionMarblePrivateDetails`` as an argument.
   742  
   743  We will step through adding blocks to the chain, and then watch the price
   744  information get purged by issuing four new transactions (Create a new marble,
   745  followed by three marble transfers) which adds four new blocks to the chain.
   746  After the fourth transaction (third marble transfer), we will verify that the
   747  price private data is purged.
   748  
   749  :guilabel:`Try it yourself`
   750  
   751  Switch back to Org1 using the following commands. Copy and paste the following code
   752  block and run it inside your peer container:
   753  
   754  .. code :: bash
   755  
   756      export CORE_PEER_LOCALMSPID="Org1MSP"
   757      export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
   758      export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
   759      export CORE_PEER_ADDRESS=localhost:7051
   760  
   761  Open a new terminal window and view the private data logs for this peer by
   762  running the following command. Note the highest block number.
   763  
   764  .. code:: bash
   765  
   766      docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'
   767  
   768  
   769  Back in the peer container, query for the **marble1** price data by running the
   770  following command. (A Query does not create a new transaction on the ledger
   771  since no data is transacted).
   772  
   773  .. code:: bash
   774  
   775      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   776  
   777  You should see results similar to:
   778  
   779  .. code:: bash
   780  
   781      {"docType":"marblePrivateDetails","name":"marble1","price":99}
   782  
   783  The ``price`` data is still in the private data ledger.
   784  
   785  Create a new **marble2** by issuing the following command. This transaction
   786  creates a new block on the chain.
   787  
   788  .. code:: bash
   789  
   790      export MARBLE=$(echo -n "{\"name\":\"marble2\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\",\"price\":99}" | base64 | tr -d \\n)
   791      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp -c '{"Args":["initMarble"]}' --transient "{\"marble\":\"$MARBLE\"}"
   792  
   793  Switch back to the Terminal window and view the private data logs for this peer
   794  again. You should see the block height increase by 1.
   795  
   796  .. code:: bash
   797  
   798      docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'
   799  
   800  Back in the peer container, query for the **marble1** price data again by
   801  running the following command:
   802  
   803  .. code:: bash
   804  
   805      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   806  
   807  The private data has not been purged, therefore the results are unchanged from
   808  previous query:
   809  
   810  .. code:: bash
   811  
   812      {"docType":"marblePrivateDetails","name":"marble1","price":99}
   813  
   814  Transfer marble2 to "joe" by running the following command. This transaction
   815  will add a second new block on the chain.
   816  
   817  .. code:: bash
   818  
   819      export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"joe\"}" | base64 | tr -d \\n)
   820      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"
   821  
   822  Switch back to the Terminal window and view the private data logs for this peer
   823  again. You should see the block height increase by 1.
   824  
   825  .. code:: bash
   826  
   827      docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'
   828  
   829  Back in the peer container, query for the marble1 price data by running the
   830  following command:
   831  
   832  .. code:: bash
   833  
   834      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   835  
   836  You should still be able to see the price private data.
   837  
   838  .. code:: bash
   839  
   840      {"docType":"marblePrivateDetails","name":"marble1","price":99}
   841  
   842  Transfer marble2 to "tom" by running the following command. This transaction
   843  will create a third new block on the chain.
   844  
   845  .. code:: bash
   846  
   847      export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"tom\"}" | base64 | tr -d \\n)
   848      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"
   849  
   850  Switch back to the Terminal window and view the private data logs for this peer
   851  again. You should see the block height increase by 1.
   852  
   853  .. code:: bash
   854  
   855      docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'
   856  
   857  Back in the peer container, query for the marble1 price data by running the
   858  following command:
   859  
   860  .. code:: bash
   861  
   862      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   863  
   864  You should still be able to see the price data.
   865  
   866  .. code:: bash
   867  
   868      {"docType":"marblePrivateDetails","name":"marble1","price":99}
   869  
   870  Finally, transfer marble2 to "jerry" by running the following command. This
   871  transaction will create a fourth new block on the chain. The ``price`` private
   872  data should be purged after this transaction.
   873  
   874  .. code:: bash
   875  
   876      export MARBLE_OWNER=$(echo -n "{\"name\":\"marble2\",\"owner\":\"jerry\"}" | base64 | tr -d \\n)
   877      peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n marblesp -c '{"Args":["transferMarble"]}' --transient "{\"marble_owner\":\"$MARBLE_OWNER\"}"
   878  
   879  Switch back to the Terminal window and view the private data logs for this peer
   880  again. You should see the block height increase by 1.
   881  
   882  .. code:: bash
   883  
   884      docker logs peer0.org1.example.com 2>&1 | grep -i -a -E 'private|pvt|privdata'
   885  
   886  Back in the peer container, query for the marble1 price data by running the following command:
   887  
   888  .. code:: bash
   889  
   890      peer chaincode query -C mychannel -n marblesp -c '{"Args":["readMarblePrivateDetails","marble1"]}'
   891  
   892  Because the price data has been purged, you should no longer be able to see it.
   893  You should see something similar to:
   894  
   895  .. code:: bash
   896  
   897      Error: endorsement failure during query. response: status:500
   898      message:"{\"Error\":\"Marble private details does not exist: marble1\"}"
   899  
   900  .. _pd-indexes:
   901  
   902  Using indexes with private data
   903  -------------------------------
   904  
   905  Indexes can also be applied to private data collections, by packaging indexes in
   906  the ``META-INF/statedb/couchdb/collections/<collection_name>/indexes`` directory
   907  alongside the chaincode. An example index is available `here <https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02_private/go/META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexOwner.json>`__ .
   908  
   909  For deployment of chaincode to production environments, it is recommended
   910  to define any indexes alongside chaincode so that the chaincode and supporting
   911  indexes are deployed automatically as a unit, once the chaincode has been
   912  installed on a peer and instantiated on a channel. The associated indexes are
   913  automatically deployed upon chaincode instantiation on the channel when
   914  the  ``--collections-config`` flag is specified pointing to the location of
   915  the collection JSON file.
   916  
   917  
   918  .. _pd-ref-material:
   919  
   920  Additional resources
   921  --------------------
   922  
   923  For additional private data education, a video tutorial has been created.
   924  
   925  .. note:: The video uses the previous lifecycle model to install private data
   926            collections with chaincode.
   927  
   928  .. raw:: html
   929  
   930     <br/><br/>
   931     <iframe width="560" height="315" src="https://www.youtube.com/embed/qyjDi93URJE" frameborder="0" allowfullscreen></iframe>
   932     <br/><br/>
   933  
   934  .. Licensed under Creative Commons Attribution 4.0 International License
   935     https://creativecommons.org/licenses/by/4.0/