mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-22 09:35:10 +00:00
Add missing apps and chaincodes to CI
Adds the apps and chaincodes to linting and testing CI that weren't added before. Linting issues were corrected where necessary to make CI pass. The Basic-Go application and Private-Javascript application are currently disabled pending fixes currently being worked on. Signed-off-by: Brett Logan <brett.t.logan@ibm.com>
This commit is contained in:
parent
8f180cd5a3
commit
11c05fa612
12 changed files with 525 additions and 385 deletions
|
|
@ -7,9 +7,9 @@ SPDX-License-Identifier: Apache-2.0
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
|
@ -18,20 +18,22 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("============ application-golang starts ============")
|
log.Println("============ application-golang starts ============")
|
||||||
|
|
||||||
|
err := os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error setting DISCOVERY_AS_LOCALHOST environemnt variable: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
|
|
||||||
wallet, err := gateway.NewFileSystemWallet("wallet")
|
wallet, err := gateway.NewFileSystemWallet("wallet")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create wallet: %v\n", err)
|
log.Fatalf("Failed to create wallet: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !wallet.Exists("appUser") {
|
if !wallet.Exists("appUser") {
|
||||||
err = populateWallet(wallet)
|
err = populateWallet(wallet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to populate wallet contents: %v\n", err)
|
log.Fatalf("Failed to populate wallet contents: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,57 +52,56 @@ func main() {
|
||||||
gateway.WithIdentity(wallet, "appUser"),
|
gateway.WithIdentity(wallet, "appUser"),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to connect to gateway: %v\n", err)
|
log.Fatalf("Failed to connect to gateway: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
defer gw.Close()
|
defer gw.Close()
|
||||||
|
|
||||||
network, err := gw.GetNetwork("mychannel")
|
network, err := gw.GetNetwork("mychannel")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to get network: %v\n", err)
|
log.Fatalf("Failed to get network: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contract := network.GetContract("basic")
|
contract := network.GetContract("basic")
|
||||||
|
|
||||||
result, err := contract.EvaluateTransaction("GetAllAssets")
|
result, err := contract.SubmitTransaction("InitLedger")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to evaluate transaction: %v\n", err)
|
log.Fatalf("failed to evaluate transaction: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
fmt.Println(string(result))
|
log.Println(string(result))
|
||||||
|
|
||||||
result, err = contract.SubmitTransaction("CreateAsset", "asset13", "yellow", "Tom", "5", "1300")
|
result, err = contract.EvaluateTransaction("GetAllAssets")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to submit transaction: %v\n", err)
|
log.Fatalf("Failed to evaluate transaction: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
fmt.Println(string(result))
|
log.Println(string(result))
|
||||||
|
|
||||||
|
result, err = contract.SubmitTransaction("CreateAsset", "asset13", "yellow", "5", "Tom", "1300")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to submit transaction: %v", err)
|
||||||
|
}
|
||||||
|
log.Println(string(result))
|
||||||
|
|
||||||
result, err = contract.EvaluateTransaction("ReadAsset", "asset4")
|
result, err = contract.EvaluateTransaction("ReadAsset", "asset4")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to evaluate transaction: %v\n", err)
|
log.Fatalf("Failed to evaluate transaction: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
fmt.Println(string(result))
|
log.Println(string(result))
|
||||||
|
|
||||||
_, err = contract.SubmitTransaction("TransferAsset", "asset1", "Tom")
|
_, err = contract.SubmitTransaction("TransferAsset", "asset1", "Tom")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to submit transaction: %v\n", err)
|
log.Fatalf("Failed to submit transaction: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err = contract.EvaluateTransaction("ReadAsset", "asset1")
|
result, err = contract.EvaluateTransaction("ReadAsset", "asset1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to evaluate transaction: %v\n", err)
|
log.Fatalf("Failed to evaluate transaction: %v", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
fmt.Println(string(result))
|
log.Println(string(result))
|
||||||
fmt.Println("============ application-golang ends ============")
|
log.Println("============ application-golang ends ============")
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateWallet(wallet *gateway.Wallet) error {
|
func populateWallet(wallet *gateway.Wallet) error {
|
||||||
fmt.Println("============ populate wallet starts ============")
|
log.Println("============ Populating wallet ============")
|
||||||
credPath := filepath.Join(
|
credPath := filepath.Join(
|
||||||
"..",
|
"..",
|
||||||
"..",
|
"..",
|
||||||
|
|
@ -127,7 +128,7 @@ func populateWallet(wallet *gateway.Wallet) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(files) != 1 {
|
if len(files) != 1 {
|
||||||
return errors.New("keystore folder should have contain one file")
|
return fmt.Errorf("keystore folder should have contain one file")
|
||||||
}
|
}
|
||||||
keyPath := filepath.Join(keyDir, files[0].Name())
|
keyPath := filepath.Join(keyDir, files[0].Name())
|
||||||
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
|
key, err := ioutil.ReadFile(filepath.Clean(keyPath))
|
||||||
|
|
@ -137,10 +138,5 @@ func populateWallet(wallet *gateway.Wallet) error {
|
||||||
|
|
||||||
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
|
identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))
|
||||||
|
|
||||||
err = wallet.Put("appUser", identity)
|
return wallet.Put("appUser", identity)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("============ populate wallet ends ============")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
coverage
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
mocha: true
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 8,
|
||||||
|
sourceType: 'script'
|
||||||
|
},
|
||||||
|
extends: 'eslint:recommended',
|
||||||
|
rules: {
|
||||||
|
indent: ['error', 'tab'],
|
||||||
|
'linebreak-style': ['error', 'unix'],
|
||||||
|
quotes: ['error', 'single'],
|
||||||
|
semi: ['error', 'always'],
|
||||||
|
'no-unused-vars': ['error', { args: 'none' }],
|
||||||
|
'no-console': 'off',
|
||||||
|
curly: 'error',
|
||||||
|
eqeqeq: 'error',
|
||||||
|
'no-throw-literal': 'error',
|
||||||
|
strict: 'error',
|
||||||
|
'no-var': 'error',
|
||||||
|
'dot-notation': 'error',
|
||||||
|
'no-trailing-spaces': 'error',
|
||||||
|
'no-use-before-define': 'error',
|
||||||
|
'no-useless-call': 'error',
|
||||||
|
'no-with': 'error',
|
||||||
|
'operator-linebreak': 'error',
|
||||||
|
yoda: 'error',
|
||||||
|
'quote-props': ['error', 'as-needed']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -67,335 +67,336 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Contract } = require('fabric-contract-api');
|
const {Contract} = require('fabric-contract-api');
|
||||||
|
|
||||||
class Chaincode extends Contract{
|
class Chaincode extends Contract {
|
||||||
|
|
||||||
// CreateAsset - create a new asset, store into chaincode state
|
// CreateAsset - create a new asset, store into chaincode state
|
||||||
async CreateAsset(ctx, assetID, color, size, owner, appraisedValue) {
|
async CreateAsset(ctx, assetID, color, size, owner, appraisedValue) {
|
||||||
const exists = await this.AssetExists(ctx, assetID)
|
const exists = await this.AssetExists(ctx, assetID);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
throw new Error(`The asset ${assetID} already exists`)
|
throw new Error(`The asset ${assetID} already exists`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==== Create asset object and marshal to JSON ====
|
// ==== Create asset object and marshal to JSON ====
|
||||||
let asset = {};
|
let asset = {
|
||||||
asset.docType = 'asset';
|
docType: 'asset',
|
||||||
asset.ID = assetID;
|
assetID: assetID,
|
||||||
asset.color = color;
|
color: color,
|
||||||
asset.size = size;
|
size: size,
|
||||||
asset.owner = owner;
|
owner: owner,
|
||||||
asset.appraisedValue = appraisedValue;
|
appraisedValue: appraisedValue
|
||||||
|
};
|
||||||
|
|
||||||
// === Save asset to state ===
|
|
||||||
await ctx.stub.putState(assetID, Buffer.from(JSON.stringify(asset)));
|
|
||||||
let indexName = 'color~name'
|
|
||||||
let colorNameIndexKey = await ctx.stub.createCompositeKey(indexName, [asset.color, asset.ID]);
|
|
||||||
|
|
||||||
// Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble.
|
// === Save asset to state ===
|
||||||
// Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value
|
await ctx.stub.putState(assetID, Buffer.from(JSON.stringify(asset)));
|
||||||
await ctx.stub.putState(colorNameIndexKey, Buffer.from('\u0000'));
|
let indexName = 'color~name';
|
||||||
}
|
let colorNameIndexKey = await ctx.stub.createCompositeKey(indexName, [asset.color, asset.assetID]);
|
||||||
|
|
||||||
// ReadAsset returns the asset stored in the world state with given id.
|
// Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble.
|
||||||
async ReadAsset(ctx, id) {
|
// Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value
|
||||||
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
|
await ctx.stub.putState(colorNameIndexKey, Buffer.from('\u0000'));
|
||||||
if (!assetJSON || assetJSON.length === 0) {
|
}
|
||||||
throw new Error(`Asset ${id} does not exist`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assetJSON.toString();
|
// ReadAsset returns the asset stored in the world state with given id.
|
||||||
}
|
async ReadAsset(ctx, id) {
|
||||||
|
const assetJSON = await ctx.stub.getState(id); // get the asset from chaincode state
|
||||||
|
if (!assetJSON || assetJSON.length === 0) {
|
||||||
|
throw new Error(`Asset ${id} does not exist`);
|
||||||
|
}
|
||||||
|
|
||||||
// delete - remove a asset key/value pair from state
|
return assetJSON.toString();
|
||||||
async DeleteAsset(ctx, id) {
|
}
|
||||||
if (!id) {
|
|
||||||
throw new Error('Asset name must not be empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
var exists = await this.AssetExists(ctx, id)
|
// delete - remove a asset key/value pair from state
|
||||||
if (!exists) {
|
async DeleteAsset(ctx, id) {
|
||||||
throw new Error(`Asset ${id} does not exist`)
|
if (!id) {
|
||||||
}
|
throw new Error('Asset name must not be empty');
|
||||||
|
}
|
||||||
|
|
||||||
// to maintain the color~name index, we need to read the asset first and get its color
|
let exists = await this.AssetExists(ctx, id);
|
||||||
let valAsbytes = await ctx.stub.getState(id); // get the asset from chaincode state
|
if (!exists) {
|
||||||
let jsonResp = {};
|
throw new Error(`Asset ${id} does not exist`);
|
||||||
if (!valAsbytes) {
|
}
|
||||||
jsonResp.error = 'Asset does not exist: ' + name;
|
|
||||||
throw new Error(jsonResp);
|
|
||||||
}
|
|
||||||
let assetJSON = {};
|
|
||||||
try {
|
|
||||||
assetJSON = JSON.parse(valAsbytes.toString());
|
|
||||||
} catch (err) {
|
|
||||||
jsonResp = {};
|
|
||||||
jsonResp.error = 'Failed to decode JSON of: ' + id;
|
|
||||||
throw new Error(jsonResp);
|
|
||||||
}
|
|
||||||
await ctx.stub.deleteState(id); //remove the asset from chaincode state
|
|
||||||
|
|
||||||
// delete the index
|
// to maintain the color~name index, we need to read the asset first and get its color
|
||||||
let indexName = 'color~name';
|
let valAsbytes = await ctx.stub.getState(id); // get the asset from chaincode state
|
||||||
let colorNameIndexKey = ctx.stub.createCompositeKey(indexName, [assetJSON.color, assetJSON.ID]);
|
let jsonResp = {};
|
||||||
if (!colorNameIndexKey) {
|
if (!valAsbytes) {
|
||||||
throw new Error(' Failed to create the createCompositeKey');
|
jsonResp.error = `Asset does not exist: ${id}`;
|
||||||
}
|
throw new Error(jsonResp);
|
||||||
// Delete index entry to state.
|
}
|
||||||
await ctx.stub.deleteState(colorNameIndexKey);
|
let assetJSON;
|
||||||
}
|
try {
|
||||||
|
assetJSON = JSON.parse(valAsbytes.toString());
|
||||||
|
} catch (err) {
|
||||||
|
jsonResp = {};
|
||||||
|
jsonResp.error = `Failed to decode JSON of: ${id}`;
|
||||||
|
throw new Error(jsonResp);
|
||||||
|
}
|
||||||
|
await ctx.stub.deleteState(id); //remove the asset from chaincode state
|
||||||
|
|
||||||
// TransferAsset transfers an asset by setting a new owner name on the asset
|
// delete the index
|
||||||
async TransferAsset(ctx, assetName, newOwner) {
|
let indexName = 'color~name';
|
||||||
|
let colorNameIndexKey = ctx.stub.createCompositeKey(indexName, [assetJSON.color, assetJSON.assetID]);
|
||||||
|
if (!colorNameIndexKey) {
|
||||||
|
throw new Error(' Failed to create the createCompositeKey');
|
||||||
|
}
|
||||||
|
// Delete index entry to state.
|
||||||
|
await ctx.stub.deleteState(colorNameIndexKey);
|
||||||
|
}
|
||||||
|
|
||||||
let assetAsBytes = await ctx.stub.getState(assetName);
|
// TransferAsset transfers a asset by setting a new owner name on the asset
|
||||||
if (!assetAsBytes || !assetAsBytes.toString()) {
|
async TransferAsset(ctx, assetName, newOwner) {
|
||||||
throw new Error(`Asset ${assetName} does not exist`);
|
|
||||||
}
|
|
||||||
let assetToTransfer = {};
|
|
||||||
try {
|
|
||||||
assetToTransfer = JSON.parse(assetAsBytes.toString()); //unmarshal
|
|
||||||
} catch (err) {
|
|
||||||
let jsonResp = {};
|
|
||||||
jsonResp.error = 'Failed to decode JSON of: ' + assetName;
|
|
||||||
throw new Error(jsonResp);
|
|
||||||
}
|
|
||||||
assetToTransfer.owner = newOwner; //change the owner
|
|
||||||
|
|
||||||
let assetJSONasBytes = Buffer.from(JSON.stringify(assetToTransfer));
|
let assetAsBytes = await ctx.stub.getState(assetName);
|
||||||
await ctx.stub.putState(assetName, assetJSONasBytes); //rewrite the asset
|
if (!assetAsBytes || !assetAsBytes.toString()) {
|
||||||
}
|
throw new Error(`Asset ${assetName} does not exist`);
|
||||||
|
}
|
||||||
|
let assetToTransfer = {};
|
||||||
|
try {
|
||||||
|
assetToTransfer = JSON.parse(assetAsBytes.toString()); //unmarshal
|
||||||
|
} catch (err) {
|
||||||
|
let jsonResp = {};
|
||||||
|
jsonResp.error = 'Failed to decode JSON of: ' + assetName;
|
||||||
|
throw new Error(jsonResp);
|
||||||
|
}
|
||||||
|
assetToTransfer.owner = newOwner; //change the owner
|
||||||
|
|
||||||
// GetAssetsByRange performs a range query based on the start and end keys provided.
|
let assetJSONasBytes = Buffer.from(JSON.stringify(assetToTransfer));
|
||||||
// Read-only function results are not typically submitted to ordering. If the read-only
|
await ctx.stub.putState(assetName, assetJSONasBytes); //rewrite the asset
|
||||||
// results are submitted to ordering, or if the query is used in an update transaction
|
}
|
||||||
// and submitted to ordering, then the committing peers will re-execute to guarantee that
|
|
||||||
// result sets are stable between endorsement time and commit time. The transaction is
|
|
||||||
// invalidated by the committing peers if the result set has changed between endorsement
|
|
||||||
// time and commit time.
|
|
||||||
// Therefore, range queries are a safe option for performing update transactions based on query results.
|
|
||||||
async GetAssetsByRange(ctx, startKey, endKey) {
|
|
||||||
|
|
||||||
let resultsIterator = await ctx.stub.getStateByRange(startKey, endKey);
|
// GetAssetsByRange performs a range query based on the start and end keys provided.
|
||||||
let results = await this.GetAllResults(resultsIterator, false);
|
// Read-only function results are not typically submitted to ordering. If the read-only
|
||||||
|
// results are submitted to ordering, or if the query is used in an update transaction
|
||||||
|
// and submitted to ordering, then the committing peers will re-execute to guarantee that
|
||||||
|
// result sets are stable between endorsement time and commit time. The transaction is
|
||||||
|
// invalidated by the committing peers if the result set has changed between endorsement
|
||||||
|
// time and commit time.
|
||||||
|
// Therefore, range queries are a safe option for performing update transactions based on query results.
|
||||||
|
async GetAssetsByRange(ctx, startKey, endKey) {
|
||||||
|
|
||||||
return JSON.stringify(results);
|
let resultsIterator = await ctx.stub.getStateByRange(startKey, endKey);
|
||||||
}
|
let results = await this.GetAllResults(resultsIterator, false);
|
||||||
|
|
||||||
// TransferAssetBasedOnColor will transfer assets of a given color to a certain new owner.
|
return JSON.stringify(results);
|
||||||
// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'.
|
}
|
||||||
// Committing peers will re-execute range queries to guarantee that result sets are stable
|
|
||||||
// between endorsement time and commit time. The transaction is invalidated by the
|
|
||||||
// committing peers if the result set has changed between endorsement time and commit time.
|
|
||||||
// Therefore, range queries are a safe option for performing update transactions based on query results.
|
|
||||||
// Example: GetStateByPartialCompositeKey/RangeQuery
|
|
||||||
async TransferAssetByColor(ctx, color, newOwner) {
|
|
||||||
// Query the color~name index by color
|
|
||||||
// This will execute a key range query on all keys starting with 'color'
|
|
||||||
let coloredAssetResultsIterator = await ctx.stub.getStateByPartialCompositeKey('color~name', [color]);
|
|
||||||
|
|
||||||
// Iterate through result set and for each asset found, transfer to newOwner
|
// TransferAssetBasedOnColor will transfer assets of a given color to a certain new owner.
|
||||||
while (true) {
|
// Uses a GetStateByPartialCompositeKey (range query) against color~name 'index'.
|
||||||
let responseRange = await coloredAssetResultsIterator.next();
|
// Committing peers will re-execute range queries to guarantee that result sets are stable
|
||||||
if (!responseRange || !responseRange.value || !responseRange.value.key) {
|
// between endorsement time and commit time. The transaction is invalidated by the
|
||||||
return;
|
// committing peers if the result set has changed between endorsement time and commit time.
|
||||||
}
|
// Therefore, range queries are a safe option for performing update transactions based on query results.
|
||||||
|
// Example: GetStateByPartialCompositeKey/RangeQuery
|
||||||
|
async TransferAssetByColor(ctx, color, newOwner) {
|
||||||
|
// Query the color~name index by color
|
||||||
|
// This will execute a key range query on all keys starting with 'color'
|
||||||
|
let coloredAssetResultsIterator = await ctx.stub.getStateByPartialCompositeKey('color~name', [color]);
|
||||||
|
|
||||||
let objectType;
|
// Iterate through result set and for each asset found, transfer to newOwner
|
||||||
let attributes;
|
let responseRange = await coloredAssetResultsIterator.next();
|
||||||
({
|
while (!responseRange.done) {
|
||||||
objectType,
|
if (!responseRange || !responseRange.value || !responseRange.value.key) {
|
||||||
attributes
|
return;
|
||||||
} = await ctx.stub.splitCompositeKey(responseRange.value.key));
|
}
|
||||||
|
|
||||||
console.log(objectType)
|
let objectType;
|
||||||
let returnedAssetName = attributes[1];
|
let attributes;
|
||||||
|
(
|
||||||
|
{objectType, attributes} = await ctx.stub.splitCompositeKey(responseRange.value.key)
|
||||||
|
);
|
||||||
|
|
||||||
// Now call the transfer function for the found asset.
|
console.log(objectType);
|
||||||
// Re-use the same function that is used to transfer individual assets
|
let returnedAssetName = attributes[1];
|
||||||
await this.TransferAsset(ctx, returnedAssetName, newOwner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryAssetsByOwner queries for assets based on a passed in owner.
|
// Now call the transfer function for the found asset.
|
||||||
// This is an example of a parameterized query where the query logic is baked into the chaincode,
|
// Re-use the same function that is used to transfer individual assets
|
||||||
// and accepting a single query parameter (owner).
|
await this.TransferAsset(ctx, returnedAssetName, newOwner);
|
||||||
// Only available on state databases that support rich query (e.g. CouchDB)
|
responseRange = await coloredAssetResultsIterator.next();
|
||||||
// Example: Parameterized rich query
|
}
|
||||||
async QueryAssetsByOwner(ctx, owner) {
|
}
|
||||||
let queryString = {};
|
|
||||||
queryString.selector = {};
|
|
||||||
queryString.selector.docType = 'asset';
|
|
||||||
queryString.selector.owner = owner;
|
|
||||||
let queryResults = await this.GetQueryResultForQueryString(ctx, JSON.stringify(queryString));
|
|
||||||
return queryResults; //shim.success(queryResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example: Ad hoc rich query
|
// QueryAssetsByOwner queries for assets based on a passed in owner.
|
||||||
// QueryAssets uses a query string to perform a query for assets.
|
// This is an example of a parameterized query where the query logic is baked into the chaincode,
|
||||||
// Query string matching state database syntax is passed in and executed as is.
|
// and accepting a single query parameter (owner).
|
||||||
// Supports ad hoc queries that can be defined at runtime by the client.
|
// Only available on state databases that support rich query (e.g. CouchDB)
|
||||||
// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries.
|
// Example: Parameterized rich query
|
||||||
// Only available on state databases that support rich query (e.g. CouchDB)
|
async QueryAssetsByOwner(ctx, owner) {
|
||||||
async QueryAssets(ctx, queryString) {
|
let queryString = {};
|
||||||
let queryResults = await this.GetQueryResultForQueryString(ctx, queryString);
|
queryString.selector = {};
|
||||||
return queryResults;
|
queryString.selector.docType = 'asset';
|
||||||
}
|
queryString.selector.owner = owner;
|
||||||
|
return await this.GetQueryResultForQueryString(ctx, JSON.stringify(queryString)); //shim.success(queryResults);
|
||||||
|
}
|
||||||
|
|
||||||
// GetQueryResultForQueryString executes the passed in query string.
|
// Example: Ad hoc rich query
|
||||||
// Result set is built and returned as a byte array containing the JSON results.
|
// QueryAssets uses a query string to perform a query for assets.
|
||||||
async GetQueryResultForQueryString(ctx, queryString) {
|
// Query string matching state database syntax is passed in and executed as is.
|
||||||
|
// Supports ad hoc queries that can be defined at runtime by the client.
|
||||||
|
// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries.
|
||||||
|
// Only available on state databases that support rich query (e.g. CouchDB)
|
||||||
|
async QueryAssets(ctx, queryString) {
|
||||||
|
return await this.GetQueryResultForQueryString(ctx, queryString);
|
||||||
|
}
|
||||||
|
|
||||||
let resultsIterator = await ctx.stub.getQueryResult(queryString);
|
// GetQueryResultForQueryString executes the passed in query string.
|
||||||
let results = await this.GetAllResults(resultsIterator, false);
|
// Result set is built and returned as a byte array containing the JSON results.
|
||||||
|
async GetQueryResultForQueryString(ctx, queryString) {
|
||||||
|
|
||||||
return JSON.stringify(results);
|
let resultsIterator = await ctx.stub.getQueryResult(queryString);
|
||||||
}
|
let results = await this.GetAllResults(resultsIterator, false);
|
||||||
|
|
||||||
// Example: Pagination with Range Query
|
return JSON.stringify(results);
|
||||||
// GetAssetsByRangeWithPagination performs a range query based on the start & end key,
|
}
|
||||||
// page size and a bookmark.
|
|
||||||
// The number of fetched records will be equal to or lesser than the page size.
|
|
||||||
// Paginated range queries are only valid for read only transactions.
|
|
||||||
async GetAssetsByRangeWithPagination(ctx, startKey, endKey, pageSize, bookmark) {
|
|
||||||
|
|
||||||
const { iterator, metadata } = await ctx.stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark);
|
// Example: Pagination with Range Query
|
||||||
const results = await this.GetAllResults(iterator, false);
|
// GetAssetsByRangeWithPagination performs a range query based on the start & end key,
|
||||||
|
// page size and a bookmark.
|
||||||
|
// The number of fetched records will be equal to or lesser than the page size.
|
||||||
|
// Paginated range queries are only valid for read only transactions.
|
||||||
|
async GetAssetsByRangeWithPagination(ctx, startKey, endKey, pageSize, bookmark) {
|
||||||
|
|
||||||
results.ResponseMetadata = {
|
const {iterator, metadata} = await ctx.stub.getStateByRangeWithPagination(startKey, endKey, pageSize, bookmark);
|
||||||
RecordsCount: metadata.fetched_records_count,
|
const results = await this.GetAllResults(iterator, false);
|
||||||
Bookmark: metadata.bookmark,
|
|
||||||
};
|
|
||||||
return JSON.stringify(results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example: Pagination with Ad hoc Rich Query
|
results.ResponseMetadata = {
|
||||||
// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query
|
RecordsCount: metadata.fetched_records_count,
|
||||||
// for assets. Query string matching state database syntax is passed in and executed as is.
|
Bookmark: metadata.bookmark,
|
||||||
// The number of fetched records would be equal to or lesser than the specified page size.
|
};
|
||||||
// Supports ad hoc queries that can be defined at runtime by the client.
|
return JSON.stringify(results);
|
||||||
// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries.
|
}
|
||||||
// Only available on state databases that support rich query (e.g. CouchDB)
|
|
||||||
// Paginated queries are only valid for read only transactions.
|
|
||||||
async QueryAssetsWithPagination(ctx, queryString, pageSize, bookmark) {
|
|
||||||
|
|
||||||
const { iterator, metadata } = await ctx.stub.getQueryResultWithPagination(queryString, pageSize, bookmark);
|
// Example: Pagination with Ad hoc Rich Query
|
||||||
const results = await this.GetAllResults(iterator, false);
|
// QueryAssetsWithPagination uses a query string, page size and a bookmark to perform a query
|
||||||
|
// for assets. Query string matching state database syntax is passed in and executed as is.
|
||||||
|
// The number of fetched records would be equal to or lesser than the specified page size.
|
||||||
|
// Supports ad hoc queries that can be defined at runtime by the client.
|
||||||
|
// If this is not desired, follow the QueryAssetsForOwner example for parameterized queries.
|
||||||
|
// Only available on state databases that support rich query (e.g. CouchDB)
|
||||||
|
// Paginated queries are only valid for read only transactions.
|
||||||
|
async QueryAssetsWithPagination(ctx, queryString, pageSize, bookmark) {
|
||||||
|
|
||||||
results.ResponseMetadata = {
|
const {iterator, metadata} = await ctx.stub.getQueryResultWithPagination(queryString, pageSize, bookmark);
|
||||||
RecordsCount: metadata.fetched_records_count,
|
const results = await this.GetAllResults(iterator, false);
|
||||||
Bookmark: metadata.bookmark,
|
|
||||||
};
|
|
||||||
|
|
||||||
return JSON.stringify(results);
|
results.ResponseMetadata = {
|
||||||
}
|
RecordsCount: metadata.fetched_records_count,
|
||||||
|
Bookmark: metadata.bookmark,
|
||||||
|
};
|
||||||
|
|
||||||
// GetAssetHistory returns the chain of custody for an asset since issuance.
|
return JSON.stringify(results);
|
||||||
async GetAssetHistory(ctx, assetName) {
|
}
|
||||||
|
|
||||||
const resultsIterator = await ctx.stub.getHistoryForKey(assetName);
|
// GetAssetHistory returns the chain of custody for an asset since issuance.
|
||||||
const results = await this.GetAllResults(resultsIterator, true);
|
async GetAssetHistory(ctx, assetName) {
|
||||||
|
|
||||||
return JSON.stringify(results);
|
let resultsIterator = await ctx.stub.getHistoryForKey(assetName);
|
||||||
}
|
let results = await this.GetAllResults(resultsIterator, true);
|
||||||
|
|
||||||
// AssetExists returns true when asset with given ID exists in world state
|
return JSON.stringify(results);
|
||||||
async AssetExists(ctx, assetName) {
|
}
|
||||||
// ==== Check if asset already exists ====
|
|
||||||
const assetState = await ctx.stub.getState(assetName);
|
|
||||||
if ( !assetState || assetState.length === 0 ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
async GetAllResults(iterator, isHistory) {
|
// AssetExists returns true when asset with given ID exists in world state
|
||||||
const allResults = [];
|
async AssetExists(ctx, assetName) {
|
||||||
let res = await iterator.next();
|
// ==== Check if asset already exists ====
|
||||||
while (!res.done) {
|
let assetState = await ctx.stub.getState(assetName);
|
||||||
const jsonRes = {};
|
return assetState && assetState.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (isHistory) {
|
async GetAllResults(iterator, isHistory) {
|
||||||
jsonRes.TxId = res.value.txId;
|
let allResults = [];
|
||||||
jsonRes.Timestamp = res.value.timestamp;
|
let res = await iterator.next();
|
||||||
jsonRes.IsDelete = res.value.isDelete;
|
while (!res.done) {
|
||||||
}
|
if (res.value && res.value.value.toString()) {
|
||||||
|
let jsonRes = {};
|
||||||
|
console.log(res.value.value.toString('utf8'));
|
||||||
|
if (isHistory && isHistory === true) {
|
||||||
|
jsonRes.TxId = res.value.tx_id;
|
||||||
|
jsonRes.Timestamp = res.value.timestamp;
|
||||||
|
try {
|
||||||
|
jsonRes.Value = JSON.parse(res.value.value.toString('utf8'));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
jsonRes.Value = res.value.value.toString('utf8');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jsonRes.Key = res.value.key;
|
||||||
|
try {
|
||||||
|
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
jsonRes.Record = res.value.value.toString('utf8');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allResults.push(jsonRes);
|
||||||
|
}
|
||||||
|
res = await iterator.next();
|
||||||
|
}
|
||||||
|
iterator.close();
|
||||||
|
return allResults;
|
||||||
|
}
|
||||||
|
|
||||||
if (res.value.value.length > 0) {
|
// InitLedger creates sample assets in the ledger
|
||||||
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
|
async InitLedger(ctx) {
|
||||||
} else {
|
const assets = [
|
||||||
jsonRes.Record = {ID: res.value.key};
|
{
|
||||||
}
|
assetID: 'asset1',
|
||||||
|
color: 'blue',
|
||||||
|
size: 5,
|
||||||
|
owner: 'Tom',
|
||||||
|
appraisedValue: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetID: 'asset2',
|
||||||
|
color: 'red',
|
||||||
|
size: 5,
|
||||||
|
owner: 'Brad',
|
||||||
|
appraisedValue: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetID: 'asset3',
|
||||||
|
color: 'green',
|
||||||
|
size: 10,
|
||||||
|
owner: 'Jin Soo',
|
||||||
|
appraisedValue: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetID: 'asset4',
|
||||||
|
color: 'yellow',
|
||||||
|
size: 10,
|
||||||
|
owner: 'Max',
|
||||||
|
appraisedValue: 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetID: 'asset5',
|
||||||
|
color: 'black',
|
||||||
|
size: 15,
|
||||||
|
owner: 'Adriana',
|
||||||
|
appraisedValue: 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assetID: 'asset6',
|
||||||
|
color: 'white',
|
||||||
|
size: 15,
|
||||||
|
owner: 'Michel',
|
||||||
|
appraisedValue: 250
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
jsonRes.Key = res.value.key;
|
for (let asset in assets) {
|
||||||
|
await this.CreateAsset(
|
||||||
console.log('Result: ' + JSON.stringify(jsonRes));
|
ctx,
|
||||||
allResults.push(jsonRes);
|
asset.assetID,
|
||||||
res = await iterator.next();
|
asset.color,
|
||||||
}
|
asset.size,
|
||||||
|
asset.owner,
|
||||||
await iterator.close();
|
asset.appraisedValue
|
||||||
return allResults;
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// InitLedger creates sample assets in the ledger
|
|
||||||
async InitLedger(ctx) {
|
|
||||||
const assets = [
|
|
||||||
{
|
|
||||||
ID: 'asset1',
|
|
||||||
color: 'blue',
|
|
||||||
size: 5,
|
|
||||||
owner: 'Tom',
|
|
||||||
appraisedValue: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'asset2',
|
|
||||||
color: 'red',
|
|
||||||
size: 5,
|
|
||||||
owner: 'Brad',
|
|
||||||
appraisedValue: 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'asset3',
|
|
||||||
color: 'green',
|
|
||||||
size: 10,
|
|
||||||
owner: 'Jin Soo',
|
|
||||||
appraisedValue: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'asset4',
|
|
||||||
color: 'yellow',
|
|
||||||
size: 10,
|
|
||||||
owner: 'Max',
|
|
||||||
appraisedValue: 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'asset5',
|
|
||||||
color: 'black',
|
|
||||||
size: 15,
|
|
||||||
owner: 'Adriana',
|
|
||||||
appraisedValue: 250
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 'asset6',
|
|
||||||
color: 'white',
|
|
||||||
size: 15,
|
|
||||||
owner: 'Michel',
|
|
||||||
appraisedValue: 250
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 0; i < assets.length; i++) {
|
|
||||||
await this.CreateAsset(
|
|
||||||
ctx,
|
|
||||||
assets[i].ID,
|
|
||||||
assets[i].color,
|
|
||||||
assets[i].size,
|
|
||||||
assets[i].owner,
|
|
||||||
assets[i].appraisedValue
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Chaincode;
|
module.exports = Chaincode;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { Object, Property } from 'fabric-contract-api';
|
||||||
|
|
||||||
@Object()
|
@Object()
|
||||||
export class Asset {
|
export class Asset {
|
||||||
|
|
||||||
@Property()
|
@Property()
|
||||||
public ID: string;
|
public ID: string;
|
||||||
|
|
||||||
|
|
@ -18,5 +17,4 @@ export class Asset {
|
||||||
|
|
||||||
@Property()
|
@Property()
|
||||||
public OwnerOrg: string;
|
public OwnerOrg: string;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class AssetContract extends Contract {
|
||||||
if (exists) {
|
if (exists) {
|
||||||
throw new Error(`The asset ${assetId} already exists`);
|
throw new Error(`The asset ${assetId} already exists`);
|
||||||
}
|
}
|
||||||
const ownerOrg = this.getClientOrgId(ctx);
|
const ownerOrg = AssetContract.getClientOrgId(ctx);
|
||||||
const asset = new Asset();
|
const asset = new Asset();
|
||||||
asset.ID = assetId;
|
asset.ID = assetId;
|
||||||
asset.Value = value;
|
asset.Value = value;
|
||||||
|
|
@ -27,7 +27,7 @@ export class AssetContract extends Contract {
|
||||||
// Create the asset
|
// Create the asset
|
||||||
await ctx.stub.putState(assetId, buffer);
|
await ctx.stub.putState(assetId, buffer);
|
||||||
// Set the endorsement policy of the assetId Key, such that current owner Org Peer is required to endorse future updates
|
// Set the endorsement policy of the assetId Key, such that current owner Org Peer is required to endorse future updates
|
||||||
await this.setAssetStateBasedEndorsement(ctx, asset.ID, [ownerOrg]);
|
await AssetContract.setAssetStateBasedEndorsement(ctx, asset.ID, [ownerOrg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAsset returns asset with given assetId
|
// ReadAsset returns asset with given assetId
|
||||||
|
|
@ -78,7 +78,7 @@ export class AssetContract extends Contract {
|
||||||
// Update the asset
|
// Update the asset
|
||||||
await ctx.stub.putState(assetId, Buffer.from(JSON.stringify(asset)));
|
await ctx.stub.putState(assetId, Buffer.from(JSON.stringify(asset)));
|
||||||
// Re-Set the endorsement policy of the assetId Key, such that a new owner Org Peer is required to endorse future updates
|
// Re-Set the endorsement policy of the assetId Key, such that a new owner Org Peer is required to endorse future updates
|
||||||
await this.setAssetStateBasedEndorsement(ctx, asset.ID, [newOwnerOrg]);
|
await AssetContract.setAssetStateBasedEndorsement(ctx, asset.ID, [newOwnerOrg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssetExists returns true when asset with given ID exists
|
// AssetExists returns true when asset with given ID exists
|
||||||
|
|
@ -89,14 +89,14 @@ export class AssetContract extends Contract {
|
||||||
|
|
||||||
// setAssetStateBasedEndorsement sets an endorsement policy to the assetId Key
|
// setAssetStateBasedEndorsement sets an endorsement policy to the assetId Key
|
||||||
// setAssetStateBasedEndorsement enforces that the owner Org Peers must endorse future update transactions for the specified assetId Key
|
// setAssetStateBasedEndorsement enforces that the owner Org Peers must endorse future update transactions for the specified assetId Key
|
||||||
private async setAssetStateBasedEndorsement(ctx: Context, assetId: string, ownerOrgs: string[]): Promise<void> {
|
private static async setAssetStateBasedEndorsement(ctx: Context, assetId: string, ownerOrgs: string[]): Promise<void> {
|
||||||
let ep = new KeyEndorsementPolicy();
|
const ep = new KeyEndorsementPolicy();
|
||||||
ep.addOrgs("MEMBER", ...ownerOrgs);
|
ep.addOrgs('MEMBER', ...ownerOrgs);
|
||||||
await ctx.stub.setStateValidationParameter(assetId, ep.getPolicy());
|
await ctx.stub.setStateValidationParameter(assetId, ep.getPolicy());
|
||||||
}
|
}
|
||||||
|
|
||||||
// getClientOrgId gets the client's OrgId (MSPID)
|
// getClientOrgId gets the client's OrgId (MSPID)
|
||||||
private getClientOrgId(ctx: Context): string {
|
private static getClientOrgId(ctx: Context): string {
|
||||||
return ctx.clientIdentity.getMSPID();
|
return ctx.clientIdentity.getMSPID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,14 @@ jobs:
|
||||||
vmImage: ubuntu-18.04
|
vmImage: ubuntu-18.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
Basic-Application-Go:
|
||||||
|
DIRECTORY: asset-transfer-basic
|
||||||
|
LANGUAGE: go
|
||||||
|
TYPE: application
|
||||||
|
Basic-Application-Java:
|
||||||
|
DIRECTORY: asset-transfer-basic
|
||||||
|
LANGUAGE: java
|
||||||
|
TYPE: application
|
||||||
Basic-Application-Javascript:
|
Basic-Application-Javascript:
|
||||||
DIRECTORY: asset-transfer-basic
|
DIRECTORY: asset-transfer-basic
|
||||||
LANGUAGE: javascript
|
LANGUAGE: javascript
|
||||||
|
|
@ -96,18 +104,30 @@ jobs:
|
||||||
DIRECTORY: asset-transfer-basic
|
DIRECTORY: asset-transfer-basic
|
||||||
LANGUAGE: typescript
|
LANGUAGE: typescript
|
||||||
TYPE: chaincode
|
TYPE: chaincode
|
||||||
|
Ledger-Application-Java:
|
||||||
|
DIRECTORY: asset-transfer-ledger-queries
|
||||||
|
LANGUAGE: java
|
||||||
|
TYPE: application
|
||||||
Ledger-Chaincode-Go:
|
Ledger-Chaincode-Go:
|
||||||
DIRECTORY: asset-transfer-ledger-queries
|
DIRECTORY: asset-transfer-ledger-queries
|
||||||
LANGUAGE: go
|
LANGUAGE: go
|
||||||
TYPE: chaincode
|
TYPE: chaincode
|
||||||
PrivateData-Chaincode-Go:
|
Ledger-Chaincode-Javascript:
|
||||||
DIRECTORY: asset-transfer-private-data
|
DIRECTORY: asset-transfer-ledger-queries
|
||||||
LANGUAGE: go
|
LANGUAGE: javascript
|
||||||
TYPE: chaincode
|
TYPE: chaincode
|
||||||
PrivateData-Application-Javascript:
|
PrivateData-Application-Javascript:
|
||||||
DIRECTORY: asset-transfer-private-data
|
DIRECTORY: asset-transfer-private-data
|
||||||
LANGUAGE: javascript
|
LANGUAGE: javascript
|
||||||
TYPE: application
|
TYPE: application
|
||||||
|
PrivateData-Chaincode-Go:
|
||||||
|
DIRECTORY: asset-transfer-private-data
|
||||||
|
LANGUAGE: go
|
||||||
|
TYPE: chaincode
|
||||||
|
SBE-Chaincode-Typescript:
|
||||||
|
DIRECTORY: asset-transfer-sbe
|
||||||
|
LANGUAGE: typescript
|
||||||
|
TYPE: chaincode
|
||||||
Secured-Chaincode-Go:
|
Secured-Chaincode-Go:
|
||||||
DIRECTORY: asset-transfer-secured-agreement
|
DIRECTORY: asset-transfer-secured-agreement
|
||||||
LANGUAGE: go
|
LANGUAGE: go
|
||||||
|
|
@ -158,6 +178,9 @@ jobs:
|
||||||
Ledger-Go:
|
Ledger-Go:
|
||||||
CHAINCODE_NAME: ledger
|
CHAINCODE_NAME: ledger
|
||||||
CHAINCODE_LANGUAGE: go
|
CHAINCODE_LANGUAGE: go
|
||||||
|
Ledger-Javascript:
|
||||||
|
CHAINCODE_NAME: ledger
|
||||||
|
CHAINCODE_LANGUAGE: javascript
|
||||||
steps:
|
steps:
|
||||||
- template: templates/install-deps.yml
|
- template: templates/install-deps.yml
|
||||||
- script: ../ci/scripts/run-test-network-ledger.sh
|
- script: ../ci/scripts/run-test-network-ledger.sh
|
||||||
|
|
@ -179,6 +202,21 @@ jobs:
|
||||||
workingDirectory: test-network
|
workingDirectory: test-network
|
||||||
displayName: Run Test Network Private Chaincode
|
displayName: Run Test Network Private Chaincode
|
||||||
|
|
||||||
|
- job: TestNetworkSBE
|
||||||
|
displayName: Test Network
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-18.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
SBE-Typescript:
|
||||||
|
CHAINCODE_NAME: sbe
|
||||||
|
CHAINCODE_LANGUAGE: typescript
|
||||||
|
steps:
|
||||||
|
- template: templates/install-deps.yml
|
||||||
|
- script: ../ci/scripts/run-test-network-sbe.sh
|
||||||
|
workingDirectory: test-network
|
||||||
|
displayName: Run Test Network Private Chaincode
|
||||||
|
|
||||||
- job: TestNetworkSecured
|
- job: TestNetworkSecured
|
||||||
displayName: Test Network
|
displayName: Test Network
|
||||||
pool:
|
pool:
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,42 @@ function print() {
|
||||||
echo -e "${GREEN}${1}${NC}"
|
echo -e "${GREEN}${1}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Creating network"
|
function createNetwork() {
|
||||||
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
print "Creating network"
|
||||||
print "Deploying ${CHAINCODE_NAME} chaincode"
|
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
||||||
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
print "Deploying ${CHAINCODE_NAME} chaincode"
|
||||||
|
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopNetwork() {
|
||||||
|
print "Stopping network"
|
||||||
|
./network.sh down
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run Go application
|
||||||
|
#createNetwork
|
||||||
|
#print "Initializing Go application"
|
||||||
|
#pushd ../asset-transfer-basic/application-go
|
||||||
|
#print "Executing AssetTransfer.go"
|
||||||
|
#go run .
|
||||||
|
#popd
|
||||||
|
#stopNetwork
|
||||||
|
|
||||||
|
# Run Java application
|
||||||
|
createNetwork
|
||||||
|
print "Initializing Java application"
|
||||||
|
pushd ../asset-transfer-basic/application-java
|
||||||
|
print "Executing Gradle Run"
|
||||||
|
gradle run
|
||||||
|
popd
|
||||||
|
stopNetwork
|
||||||
|
|
||||||
# Run Javascript application
|
# Run Javascript application
|
||||||
|
createNetwork
|
||||||
print "Initializing Javascript application"
|
print "Initializing Javascript application"
|
||||||
pushd ../asset-transfer-basic/application-javascript
|
pushd ../asset-transfer-basic/application-javascript
|
||||||
npm install
|
npm install
|
||||||
print "Executing app.js"
|
print "Executing app.js"
|
||||||
node app.js
|
node app.js
|
||||||
popd
|
popd
|
||||||
|
stopNetwork
|
||||||
print "Stopping network"
|
|
||||||
./network.sh down
|
|
||||||
rm -R ../asset-transfer-basic/application-javascript/wallet
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
FABRIC_VERSION=${FABRIC_VERSION:-2.2}
|
FABRIC_VERSION=${FABRIC_VERSION:-2.2}
|
||||||
|
CHAINCODE_LANGUAGE=${CHAINCODE_LANGUAGE:-go}
|
||||||
CHAINCODE_NAME=${CHAINCODE_NAME:-ledger}
|
CHAINCODE_NAME=${CHAINCODE_NAME:-ledger}
|
||||||
|
|
||||||
function print() {
|
function print() {
|
||||||
|
|
@ -10,31 +11,33 @@ function print() {
|
||||||
echo -e "${GREEN}${1}${NC}"
|
echo -e "${GREEN}${1}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Creating network"
|
function createNetwork() {
|
||||||
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
print "Creating network"
|
||||||
|
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
||||||
|
print "Deploying ${CHAINCODE_NAME} chaincode"
|
||||||
|
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
print "Deploying ${CHAINCODE_NAME} go chaincode"
|
function stopNetwork() {
|
||||||
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1.0 -ccs 1 -ccl go
|
print "Stopping network"
|
||||||
|
./network.sh down
|
||||||
|
}
|
||||||
|
|
||||||
# Run Javascript application against the go chaincode
|
# Run Java application
|
||||||
|
createNetwork
|
||||||
|
print "Initializing Java application"
|
||||||
|
pushd ../asset-transfer-ledger-queries/application-java
|
||||||
|
print "Executing Gradle Run"
|
||||||
|
gradle run
|
||||||
|
popd
|
||||||
|
stopNetwork
|
||||||
|
|
||||||
|
# Run Javascript application
|
||||||
|
createNetwork
|
||||||
print "Initializing Javascript application"
|
print "Initializing Javascript application"
|
||||||
pushd ../asset-transfer-ledger-queries/application-javascript
|
pushd ../asset-transfer-ledger-queries/application-javascript
|
||||||
npm install
|
npm install
|
||||||
print "Executing app.js"
|
print "Executing app.js"
|
||||||
node app.js
|
node app.js
|
||||||
popd
|
popd
|
||||||
|
stopNetwork
|
||||||
print "Deploying ${CHAINCODE_NAME} javascript chaincode"
|
|
||||||
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 2.0 -ccs 2 -ccl javascript
|
|
||||||
|
|
||||||
# Run Javascript application against the javascript chaincode
|
|
||||||
print "Initializing Javascript application"
|
|
||||||
pushd ../asset-transfer-ledger-queries/application-javascript
|
|
||||||
npm install
|
|
||||||
print "Executing app.js"
|
|
||||||
node app.js skipInit
|
|
||||||
popd
|
|
||||||
|
|
||||||
print "Stopping network"
|
|
||||||
./network.sh down
|
|
||||||
rm -R ../asset-transfer-ledger-queries/application-javascript/wallet
|
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,24 @@ function print() {
|
||||||
echo -e "${GREEN}${1}${NC}"
|
echo -e "${GREEN}${1}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Creating network"
|
function createNetwork() {
|
||||||
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
print "Creating network"
|
||||||
|
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
||||||
|
print "Deploying ${CHAINCODE_NAME} chaincode"
|
||||||
|
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
print "Deploying private-data ${CHAINCODE_NAME} chaincode"
|
function stopNetwork() {
|
||||||
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}" -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-go/collections_config.json
|
print "Stopping network"
|
||||||
|
./network.sh down
|
||||||
|
}
|
||||||
|
|
||||||
# Run Javascript application
|
# Run Javascript application
|
||||||
print "Initializing Javascript application"
|
createNetwork
|
||||||
pushd ../asset-transfer-private-data/application-javascript
|
#print "Initializing Javascript application"
|
||||||
npm install
|
#pushd ../asset-transfer-private-data/application-javascript
|
||||||
print "Executing app.js"
|
#npm install
|
||||||
node app.js
|
#print "Executing app.js"
|
||||||
popd
|
#node app.js
|
||||||
|
#popd
|
||||||
print "Stopping network"
|
stopNetwork
|
||||||
./network.sh down
|
|
||||||
|
|
|
||||||
28
ci/scripts/run-test-network-sbe.sh
Executable file
28
ci/scripts/run-test-network-sbe.sh
Executable file
|
|
@ -0,0 +1,28 @@
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
FABRIC_VERSION=${FABRIC_VERSION:-2.2}
|
||||||
|
CHAINCODE_LANGUAGE=${CHAINCODE_LANGUAGE:-typescript}
|
||||||
|
CHAINCODE_NAME=${CHAINCODE_NAME:-sbe}
|
||||||
|
|
||||||
|
function print() {
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
NC='\033[0m'
|
||||||
|
echo
|
||||||
|
echo -e "${GREEN}${1}${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNetwork() {
|
||||||
|
print "Creating network"
|
||||||
|
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
||||||
|
print "Deploying ${CHAINCODE_NAME} chaincode"
|
||||||
|
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopNetwork() {
|
||||||
|
print "Stopping network"
|
||||||
|
./network.sh down
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run Javascript application
|
||||||
|
createNetwork
|
||||||
|
stopNetwork
|
||||||
|
|
@ -11,11 +11,18 @@ function print() {
|
||||||
echo -e "${GREEN}${1}${NC}"
|
echo -e "${GREEN}${1}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Creating network"
|
function createNetwork() {
|
||||||
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
print "Creating network"
|
||||||
|
./network.sh up createChannel -ca -s couchdb -i "${FABRIC_VERSION}"
|
||||||
|
print "Deploying ${CHAINCODE_NAME} chaincode"
|
||||||
|
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
||||||
|
}
|
||||||
|
|
||||||
print "Deploying ${CHAINCODE_NAME} chaincode"
|
function stopNetwork() {
|
||||||
./network.sh deployCC -ccn "${CHAINCODE_NAME}" -ccv 1 -ccs 1 -ccl "${CHAINCODE_LANGUAGE}"
|
print "Stopping network"
|
||||||
|
./network.sh down
|
||||||
|
}
|
||||||
|
|
||||||
print "Stopping network"
|
# Run Javascript application
|
||||||
./network.sh down
|
createNetwork
|
||||||
|
stopNetwork
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue