Merge branch 'main' into feature/kind-test-network

This commit is contained in:
Matthew B White 2021-09-09 13:43:47 +01:00 committed by GitHub
commit 866a1ab2dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 131 additions and 27 deletions

View file

@ -13,12 +13,14 @@ type SmartContract struct {
}
// Asset describes basic details of what makes up a simple asset
//Insert struct field in alphabetic order => to achieve determinism accross languages
// golang keeps the order when marshal to json but doesn't order automatically
type Asset struct {
AppraisedValue int `json:"AppraisedValue"`
Color string `json:"Color"`
ID string `json:"ID"`
Color string `json:"color"`
Size int `json:"size"`
Owner string `json:"owner"`
AppraisedValue int `json:"appraisedValue"`
Owner string `json:"Owner"`
Size int `json:"Size"`
}
// InitLedger adds a base set of assets to the ledger

View file

@ -7,6 +7,7 @@ package org.hyperledger.fabric.samples.assettransfer;
import java.util.ArrayList;
import java.util.List;
import org.hyperledger.fabric.contract.Context;
import org.hyperledger.fabric.contract.ContractInterface;
import org.hyperledger.fabric.contract.annotation.Contact;
@ -86,8 +87,9 @@ public final class AssetTransfer implements ContractInterface {
}
Asset asset = new Asset(assetID, color, size, owner, appraisedValue);
String assetJSON = genson.serialize(asset);
stub.putStringState(assetID, assetJSON);
//Use Genson to convert the Asset into string, sort it alphabetically and serialize it into a json string
String sortedJson = genson.serialize(asset);
stub.putStringState(assetID, sortedJson);
return asset;
}
@ -137,9 +139,9 @@ public final class AssetTransfer implements ContractInterface {
}
Asset newAsset = new Asset(assetID, color, size, owner, appraisedValue);
String newAssetJSON = genson.serialize(newAsset);
stub.putStringState(assetID, newAssetJSON);
//Use Genson to convert the Asset into string, sort it alphabetically and serialize it into a json string
String sortedJson = genson.serialize(newAsset);
stub.putStringState(assetID, sortedJson);
return newAsset;
}
@ -199,8 +201,9 @@ public final class AssetTransfer implements ContractInterface {
Asset asset = genson.deserialize(assetJSON, Asset.class);
Asset newAsset = new Asset(asset.getAssetID(), asset.getColor(), asset.getSize(), newOwner, asset.getAppraisedValue());
String newAssetJSON = genson.serialize(newAsset);
stub.putStringState(assetID, newAssetJSON);
//Use a Genson to conver the Asset into string, sort it alphabetically and serialize it into a json string
String sortedJson = genson.serialize(newAsset);
stub.putStringState(assetID, sortedJson);
return newAsset;
}
@ -225,8 +228,8 @@ public final class AssetTransfer implements ContractInterface {
for (KeyValue result: results) {
Asset asset = genson.deserialize(result.getStringValue(), Asset.class);
System.out.println(asset);
queryResults.add(asset);
System.out.println(asset.toString());
}
final String response = genson.serialize(queryResults);

View file

@ -6,6 +6,9 @@
'use strict';
// Deterministic JSON.stringify()
const stringify = require('json-stringify-deterministic');
const sortKeysRecursive = require('sort-keys-recursive');
const { Contract } = require('fabric-contract-api');
class AssetTransfer extends Contract {
@ -58,8 +61,11 @@ class AssetTransfer extends Contract {
for (const asset of assets) {
asset.docType = 'asset';
await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
console.info(`Asset ${asset.ID} initialized`);
// example of how to write to world state deterministically
// use convetion of alphabetic order
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
// when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash
await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset))));
}
}
@ -77,7 +83,8 @@ class AssetTransfer extends Contract {
Owner: owner,
AppraisedValue: appraisedValue,
};
await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
//we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
return JSON.stringify(asset);
}
@ -105,7 +112,8 @@ class AssetTransfer extends Contract {
Owner: owner,
AppraisedValue: appraisedValue,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset))));
}
// DeleteAsset deletes an given asset from the world state.
@ -128,7 +136,8 @@ class AssetTransfer extends Contract {
const assetString = await this.ReadAsset(ctx, id);
const asset = JSON.parse(assetString);
asset.Owner = newOwner;
return ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
}
// GetAllAssets returns all assets found in the world state.
@ -146,7 +155,7 @@ class AssetTransfer extends Contract {
console.log(err);
record = strValue;
}
allResults.push({ Key: result.value.key, Record: record });
allResults.push(record);
result = await iterator.next();
}
return JSON.stringify(allResults);

View file

@ -18,7 +18,9 @@
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "^2.0.0",
"fabric-shim": "^2.0.0"
"fabric-shim": "^2.0.0",
"json-stringify-deterministic": "^1.0.1",
"sort-keys-recursive": "^2.0.0"
},
"devDependencies": {
"chai": "^4.1.2",

View file

@ -22,7 +22,9 @@
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "^2.0.0",
"fabric-shim": "^2.0.0"
"fabric-shim": "^2.0.0",
"json-stringify-deterministic":"^1.0.0",
"sort-keys-recursive":"^2.0.0"
},
"devDependencies": {
"@types/chai": "^4.1.7",

View file

@ -1,7 +1,9 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
// Deterministic JSON.stringify()
import * as stringify from 'json-stringify-deterministic';
import * as sortKeysRecursive from 'sort-keys-recursive';
import {Context, Contract, Info, Returns, Transaction} from 'fabric-contract-api';
import {Asset} from './asset';
@ -57,7 +59,11 @@ export class AssetTransferContract extends Contract {
for (const asset of assets) {
asset.docType = 'asset';
await ctx.stub.putState(asset.ID, Buffer.from(JSON.stringify(asset)));
// example of how to write to world state deterministically
// use convetion of alphabetic order
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
// when retrieving data, in any lang, the order of data will be the same and consequently also the corresonding hash
await ctx.stub.putState(asset.ID, Buffer.from(stringify(sortKeysRecursive(asset))));
console.info(`Asset ${asset.ID} initialized`);
}
}
@ -77,7 +83,8 @@ export class AssetTransferContract extends Contract {
Owner: owner,
AppraisedValue: appraisedValue,
};
await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
}
// ReadAsset returns the asset stored in the world state with given id.
@ -106,7 +113,8 @@ export class AssetTransferContract extends Contract {
Owner: owner,
AppraisedValue: appraisedValue,
};
return ctx.stub.putState(id, Buffer.from(JSON.stringify(updatedAsset)));
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
return ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(updatedAsset))));
}
// DeleteAsset deletes an given asset from the world state.
@ -133,7 +141,8 @@ export class AssetTransferContract extends Contract {
const assetString = await this.ReadAsset(ctx, id);
const asset = JSON.parse(assetString);
asset.Owner = newOwner;
await ctx.stub.putState(id, Buffer.from(JSON.stringify(asset)));
// we insert data in alphabetic order using 'json-stringify-deterministic' and 'sort-keys-recursive'
await ctx.stub.putState(id, Buffer.from(stringify(sortKeysRecursive(asset))));
}
// GetAllAssets returns all assets found in the world state.
@ -153,7 +162,7 @@ export class AssetTransferContract extends Contract {
console.log(err);
record = strValue;
}
allResults.push({Key: result.value.key, Record: record});
allResults.push(record);
result = await iterator.next();
}
return JSON.stringify(allResults);

View file

@ -3,3 +3,22 @@
You can use the `./network.sh` script to stand up a simple Fabric test network. The test network has two peer organizations with one peer each and a single node raft ordering service. You can also use the `./network.sh` script to create channels and deploy chaincode. For more information, see [Using the Fabric test network](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html). The test network is being introduced in Fabric v2.0 as the long term replacement for the `first-network` sample.
Before you can deploy the test network, you need to follow the instructions to [Install the Samples, Binaries and Docker Images](https://hyperledger-fabric.readthedocs.io/en/latest/install.html) in the Hyperledger Fabric documentation.
## Using the Peer commands
The `setOrgEnv.sh` script can be used to setup the environment variables for the ogrganziations, this will will help to be able to use the `peer` commands directly.
First, ensure that the peer binaries are on your path, and the Fabric Config path is set Assuming that you're in the `test-network` directory.
```bash
export PATH=$PATH:$(realpath ../bin)
export FABRIC_CFG_PATH=$(realpath ../config)
```
You can then set up the environment variables for each organization. The `./setOrgEnv.sh` command is designed to be run as follows.
```bash
export $(./setOrgEnv.sh Org2 | xargs)
```
You will now be able to run the `peer` commands in the context of Org2. If a different command prompt you can run the same command with Org1 instead.
The `setOrgEnv` script outputs a series of `<name>=<value>` strings. These can then be fed into the export command for your current shell

View file

@ -151,7 +151,6 @@ services:
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ../organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations
- ../scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
depends_on:

59
test-network/setOrgEnv.sh Executable file
View file

@ -0,0 +1,59 @@
#!/bin/bash
#
# SPDX-License-Identifier: Apache-2.0
# default to using Org1
ORG=${1:-Org1}
# Exit on first error, print all commands.
set -e
set -o pipefail
# Where am I?
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
ORDERER_CA=${DIR}/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
PEER0_ORG1_CA=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
PEER0_ORG2_CA=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
PEER0_ORG3_CA=${DIR}/test-network/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
if [[ ${ORG,,} == "org1" || ${ORG,,} == "digibank" ]]; then
CORE_PEER_LOCALMSPID=Org1MSP
CORE_PEER_MSPCONFIGPATH=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=localhost:7051
CORE_PEER_TLS_ROOTCERT_FILE=${DIR}/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
elif [[ ${ORG,,} == "org2" || ${ORG,,} == "magnetocorp" ]]; then
CORE_PEER_LOCALMSPID=Org2MSP
CORE_PEER_MSPCONFIGPATH=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=localhost:9051
CORE_PEER_TLS_ROOTCERT_FILE=${DIR}/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
else
echo "Unknown \"$ORG\", please choose Org1/Digibank or Org2/Magnetocorp"
echo "For example to get the environment variables to set upa Org2 shell environment run: ./setOrgEnv.sh Org2"
echo
echo "This can be automated to set them as well with:"
echo
echo 'export $(./setOrgEnv.sh Org2 | xargs)'
exit 1
fi
# output the variables that need to be set
echo "CORE_PEER_TLS_ENABLED=true"
echo "ORDERER_CA=${ORDERER_CA}"
echo "PEER0_ORG1_CA=${PEER0_ORG1_CA}"
echo "PEER0_ORG2_CA=${PEER0_ORG2_CA}"
echo "PEER0_ORG3_CA=${PEER0_ORG3_CA}"
echo "CORE_PEER_MSPCONFIGPATH=${CORE_PEER_MSPCONFIGPATH}"
echo "CORE_PEER_ADDRESS=${CORE_PEER_ADDRESS}"
echo "CORE_PEER_TLS_ROOTCERT_FILE=${CORE_PEER_TLS_ROOTCERT_FILE}"
echo "CORE_PEER_LOCALMSPID=${CORE_PEER_LOCALMSPID}"