Skip to content

Commit

Permalink
Merge "FABN-972 NodeSDK Add private data doc"
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-coleman authored and Gerrit Code Review committed Nov 15, 2018
2 parents 7364f18 + 0ecfdd3 commit 4bf0732
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 41 deletions.
32 changes: 27 additions & 5 deletions docs/tutorials/private-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@
This tutorial illustrates how to use the Node.js SDK APIs to store and retrieve private data in the Hyperledger Fabric network.

Starting in v1.2, Fabric offers the ability to create private data collections, which allows a subset of organizations on
a channel to endorse, commit, or query private data without having to create a separate channel.For more information,
a channel to endorse, commit, or query private data without having to create a separate channel. For more information,
refer to [Private Data Concept](
http://hyperledger-fabric.readthedocs.io/en/latest/private-data/private-data.html), [Private Data Architecture](
http://hyperledger-fabric.readthedocs.io/en/latest/private-data-arch.html), and [Using Private Data in Fabric](
http://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html).

### Overview
The following are the steps to use private data with the Node.js SDK. Check out below sections for the details of these steps.
The following are the steps to use private data with the Node.js SDK (fabric-client). Check out the sections below for details on these steps.

1. Create a collection definition json file
2. Implement chaincode to store and query private data
3. Install and instantiate chaincode with a collection definition
4. Invoke chaincode to store and query private data
5. Purge private data
6. Query for a collection definition

### Create a collection definition json file
A collection definition describes who can persist data, how many peers the data is distributed to, how many peers are
Expand Down Expand Up @@ -96,7 +97,7 @@ The policy property in the collectionMarbles definition allows all members of th
the private data in a private database. The collectionMarblesPrivateDetails collection allows only members of `Org1`
to have the private data in their private database.

For Node.js SDK, you must define policies in the same format as shown in the above.
For Node.js SDK, you must define policies in the same format as shown above.

### Implement chaincode to store and query private data
Fabric provides chaincode APIs to store and query private data. As an example, check out [marbles private data example](
Expand All @@ -113,7 +114,8 @@ This example implements the following functions to manage private data.
### Install and instantiate chaincode with a collection definition
Client applications interact with the blockchain ledger through chaincode. As such
we need to install and instantiate the chaincode on every peer that will execute and
endorse transactions.
endorse transactions. When instantiated a chaincode on a channel the collection will
be associated with that chaincode.

* Install chaincode. No specific parameter needed to support private data.
* Instantiate chaincode. To support private data, the request must include the `collections-config` attribute.
Expand Down Expand Up @@ -150,7 +152,27 @@ https://github.com/hyperledger/fabric-samples/blob/master/chaincode/marbles02_pr
### Purge private data
The Hyperledger Fabric allows client applications to optionally purge the private data in a collection by setting the
`blockToLive` property. This option may be needed when private data include personal or confidential information
and transacting parties want to have a limited lifespan for these data.
and transacting parties want to have a limited lifespan for the data.

When `blockToLive` is set to a non-zero value in the collection definition file, Fabric will automatically purge the related
private data after the specified number of blocks are committed. Client applications do not need to call any API.

### Query for a collection definition
The Hyperledger Fabric allows client applications to query a peer for collection definitions.
The Node.js SDK (fabric-client) has an API that will query a Hyperledger Fabric Peer for a
collection definition associated with a chaincode running on the specified channel.
See {@link Channel#queryCollectionsConfig} for detailed information.
```
const request = {
chaincodeId: chaincodeId,
target: peer
};
try {
const response = await channel.queryCollectionsConfig(request);
// response contains an array of collection definitions
return response;
} catch (error) {
throw error;
}
```
12 changes: 7 additions & 5 deletions fabric-client/lib/Channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2317,17 +2317,19 @@ const Channel = class {
* required_peer_count.
* @property {number} block_to_live - The number of blocks after which the collection
* data expires. For instance if the value is set to 10, a key last modified by block
* number 100 will be purged at block number 111. A zero value is treated same as MaxUint64
* number 100 will be purged at block number 111. A zero value is treated same as MaxUint64,
* where the data will not be purged.
* @property {Policy} policy - The
*/

/**
* query for the collections config for a chaincode.
* Query for the collection definitions associated with a chaincode.
*
* @param {CollectionQueryOptions} options - Required. The options to query the collections config.
* @property {boolean} useAdmin - Optional. To indicate that the admin identity
* should be used to make the discovery request
* @returns {Promise<CollectionQueryResponse>} returns a promise for a {@link CollectionQueryResponse} object.
* @param {boolean} useAdmin - Optional. To indicate that the admin identity
* should be used to make the query request
* @returns {Promise<CollectionQueryResponse[]>} returns a promise for an array of
* {@link CollectionQueryResponse} objects.
*/
async queryCollectionsConfig(options, useAdmin) {
const method = 'queryCollectionsConfig';
Expand Down
41 changes: 14 additions & 27 deletions test/integration/e2e/e2eUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,8 @@ function getTargetPeers(channel, targets) {
return targetPeers;
}

async function getCollectionsConfig(t, org, chaincodeId, targets) {
async function getCollectionsConfig(t, org, chaincodeId, channel_name) {
init();
const channel_name = Client.getConfigSetting('E2E_CONFIGTX_CHANNEL_NAME', testUtil.END2END.channel);

// this is a transaction, will just use org's identity to
// submit the request. intentionally we are using a different org
Expand All @@ -951,35 +950,23 @@ async function getCollectionsConfig(t, org, chaincodeId, targets) {
await client.setUserContext(admin);
t.pass('Successfully enrolled user \'admin\'');

// set up the channel to use each org's 'peer1' for
// both requests and events
for (const key in ORGS) {
if (ORGS.hasOwnProperty(key) && typeof ORGS[key].peer1 !== 'undefined') {
const data = fs.readFileSync(path.join(__dirname, ORGS[key].peer1.tls_cacerts));
const peer = client.newPeer(
ORGS[key].peer1.requests,
{
pem: Buffer.from(data).toString(),
'ssl-target-name-override': ORGS[key].peer1['server-hostname']
});
channel.addPeer(peer);
const caRootsPath = ORGS[org].peer1.tls_cacerts;
const data = fs.readFileSync(path.join(__dirname, '../e2e', caRootsPath));
const caroots = Buffer.from(data).toString();

const peer = client.newPeer(
ORGS[org].peer1.requests,
{
'pem': caroots,
'ssl-target-name-override': ORGS[org].peer1['server-hostname']
}
}
// send query
);

const request = {
chaincodeId,
txId: client.newTransactionID(),
chaincodeId: chaincodeId,
target: peer
};

// find the peers that match the targets
if (targets && targets.length !== 0) {
const targetPeers = getTargetPeers(channel, targets);
if (targetPeers.length < targets.length) {
t.fail('Failed to get all peers for targets: ' + targets);
} else {
request.targets = targetPeers;
}
}
try {
const resp = await channel.queryCollectionsConfig(request);
t.pass('Successfully retrieved collections config from peer');
Expand Down
9 changes: 5 additions & 4 deletions test/integration/e2e/getCollectionsConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ const test = _test(tape);
const e2eUtils = require('./e2eUtils.js');
const testUtil = require('../../unit/util.js');

const chaincodeId = testUtil.END2END.chaincodeIdPrivateData;

test('getCollectionsConfig from peer', async (t) => {
const targets = []; // empty array, meaning client will discover the peers
const chaincodeId = testUtil.END2END.chaincodeIdPrivateData;
const channel_name = testUtil.END2END.channel;
t.comment(' looking at chaincodeId:' + chaincodeId);
t.comment(' looking at channel_name:' + channel_name);
try {
const results = await e2eUtils.getCollectionsConfig(t, 'org1', chaincodeId, targets);
const results = await e2eUtils.getCollectionsConfig(t, 'org1', chaincodeId, channel_name);
if (results) {
t.pass('Successfully query collections config');
} else {
Expand Down

0 comments on commit 4bf0732

Please sign in to comment.