mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-26 19:45:10 +00:00
149 lines
6.2 KiB
JavaScript
149 lines
6.2 KiB
JavaScript
/*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const { Context } = require('fabric-contract-api');
|
|
const { KeyEndorsementPolicy } = require('fabric-shim');
|
|
import * as fabprotos from 'fabric-shim/bundle';
|
|
|
|
class AssetContract extends Contract {
|
|
|
|
// CreateAsset creates a new asset
|
|
// CreateAsset sets the endorsement policy of the assetId Key, such that current owner Org Peer is required to endorse future updates
|
|
async CreateAsset(ctx, assetId, value, owner) {
|
|
const exists = await this.AssetExists(ctx, assetId);
|
|
if (exists) {
|
|
throw new Error(`The asset ${assetId} already exists`);
|
|
}
|
|
const ownerOrg = AssetContract.getClientOrgId(ctx);
|
|
const asset = new Asset();
|
|
asset.ID = assetId;
|
|
asset.Value = value;
|
|
asset.Owner = owner;
|
|
asset.OwnerOrg = ownerOrg;
|
|
const buffer = Buffer.from(JSON.stringify(asset));
|
|
// Create the asset
|
|
await ctx.stub.putState(assetId, buffer);
|
|
|
|
// Set the endorsement policy of the assetId Key, such that current owner Org is required to endorse future updates
|
|
await AssetContract.setStateBasedEndorsement(ctx, assetId, [ownerOrg]);
|
|
|
|
// Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates
|
|
// await AssetContract.setStateBasedEndorsementNOutOf(ctx, assetId, 1, ["Org1MSP", "Org2MSP"]);
|
|
}
|
|
|
|
// ReadAsset returns asset with given assetId
|
|
async ReadAsset(ctx, assetId) {
|
|
const exists = await this.AssetExists(ctx, assetId);
|
|
if (!exists) {
|
|
throw new Error(`The asset ${assetId} does not exist`);
|
|
}
|
|
// Read the asset
|
|
const assetJSON = await ctx.stub.getState(assetId);
|
|
return assetJSON.toString();
|
|
}
|
|
|
|
// UpdateAsset updates an existing asset
|
|
// UpdateAsset needs an endorsement of current owner Org Peer
|
|
async UpdateAsset(ctx, assetId, newValue) {
|
|
const assetString = await this.ReadAsset(ctx, assetId);
|
|
const asset = JSON.parse(assetString);
|
|
asset.Value = newValue;
|
|
const buffer = Buffer.from(JSON.stringify(asset));
|
|
// Update the asset
|
|
await ctx.stub.putState(assetId, buffer);
|
|
}
|
|
|
|
// DeleteAsset deletes an given asset
|
|
// DeleteAsset needs an endorsement of current owner Org Peer
|
|
async DeleteAsset(ctx, assetId) {
|
|
const exists = await this.AssetExists(ctx, assetId);
|
|
if (!exists) {
|
|
throw new Error(`The asset ${assetId} does not exist`);
|
|
}
|
|
// Delete the asset
|
|
await ctx.stub.deleteState(assetId);
|
|
}
|
|
|
|
// TransferAsset updates the Owner & OwnerOrg field of asset with given assetId, OwnerOrg must be a valid Org MSP Id
|
|
// TransferAsset needs an endorsement of current owner Org Peer
|
|
// TransferAsset re-sets the endorsement policy of the assetId Key, such that new owner Org Peer is required to endorse future updates
|
|
async TransferAsset(ctx, assetId, newOwner, newOwnerOrg) {
|
|
const assetString = await this.ReadAsset(ctx, assetId);
|
|
const asset = JSON.parse(assetString);
|
|
asset.Owner = newOwner;
|
|
asset.OwnerOrg = newOwnerOrg;
|
|
// Update the 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
|
|
await AssetContract.setStateBasedEndorsement(ctx, asset.ID, [newOwnerOrg]);
|
|
|
|
// Optionally, set the endorsement policy of the assetId Key, such that any 1 Org (N) out of the specified Orgs can endorse future updates
|
|
// await AssetContract.setStateBasedEndorsementNOutOf(ctx, assetId, 1, ["Org1MSP", "Org2MSP"]);
|
|
}
|
|
|
|
// AssetExists returns true when asset with given ID exists
|
|
async AssetExists(ctx, assetId){
|
|
const buffer = await ctx.stub.getState(assetId);
|
|
return (!!buffer && buffer.length > 0);
|
|
}
|
|
|
|
// getClientOrgId gets the client's OrgId (MSPID)
|
|
static getClientOrgId(ctx){
|
|
return ctx.clientIdentity.getMSPID();
|
|
}
|
|
|
|
// setStateBasedEndorsement sets an endorsement policy to the assetId Key
|
|
// setStateBasedEndorsement enforces that the owner Org must endorse future update transactions for the specified assetId Key
|
|
static async setStateBasedEndorsement(ctx, assetId, ownerOrgs){
|
|
const ep = new KeyEndorsementPolicy();
|
|
ep.addOrgs('MEMBER', ...ownerOrgs);
|
|
await ctx.stub.setStateValidationParameter(assetId, ep.getPolicy());
|
|
}
|
|
|
|
// setStateBasedEndorsementNOutOf sets an endorsement policy to the assetId Key
|
|
// setStateBasedEndorsementNOutOf enforces that a given number of Orgs (N) out of the specified Orgs must endorse future update transactions for the specified assetId Key.
|
|
async setStateBasedEndorsementNOutOf(ctx, assetId, nOrgs, ownerOrgs) {
|
|
await ctx.stub.setStateValidationParameter(assetId, AssetContract.policy(nOrgs, ownerOrgs));
|
|
}
|
|
|
|
// Create a policy that requires a given number (N) of Org principals signatures out of the provided list of Orgs
|
|
static policy(nOrgs, mspIds) {
|
|
const principals = [];
|
|
const sigsPolicies = [];
|
|
mspIds.forEach((mspId, i) => {
|
|
const mspRole = {
|
|
role: fabprotos.common.MSPRole.MSPRoleType.MEMBER,
|
|
mspIdentifier: mspId
|
|
};
|
|
const principal = {
|
|
principalClassification: fabprotos.common.MSPPrincipal.Classification.ROLE,
|
|
principal: fabprotos.common.MSPRole.encode(mspRole).finish()
|
|
};
|
|
principals.push(principal);
|
|
const signedBy = {
|
|
signedBy: i,
|
|
};
|
|
sigsPolicies.push(signedBy);
|
|
});
|
|
|
|
// create the policy such that it requires any N signature's from all of the principals provided
|
|
const allOf = {
|
|
n: nOrgs,
|
|
rules: sigsPolicies
|
|
};
|
|
const noutof = {
|
|
nOutOf: allOf
|
|
};
|
|
const spe = {
|
|
version: 0,
|
|
rule: noutof,
|
|
identities: principals
|
|
};
|
|
return fabprotos.common.SignaturePolicyEnvelope.encode(spe).finish();
|
|
}
|
|
}
|
|
|
|
module.exports = AssetContract;
|