fabric-samples/asset-transfer-sbe/chaincode-go/asset-contract.go
Francesco Vlacancich f95fbbe3d0 final draft for JSON determinm task, using Genson instead of object mapper
Remore extra .class files

Signed-off-by: fraVlaca <ocsenarf@outlook.com>
2021-09-01 13:37:27 +01:00

198 lines
6.6 KiB
Go

/*
* SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"encoding/json"
"fmt"
"sort"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SmartContract provides functions for managing an Asset
type SmartContract struct {
contractapi.Contract
}
// CreateAsset issues a new asset to the world state with given details.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, value string, owner string) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if exists {
return fmt.Errorf("the asset %s already exists", id)
}
ownerOrg, err := s.getClientOrgId(ctx)
if err != nil {
return err
}
asset := Asset{
ID: id,
Value: value,
Owner: owner,
OwnerOrg: ownerOrg,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
} // Set the endorsement policy of the assetId Key, such that current owner Org is required to endorse future updates
setStateBasedEndorsement(ctx, id, 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
// setStateBasedEndorsementNOutOf(ctx, assetId, 1, new String[]{"Org1MSP", "Org2MSP"});
return ctx.GetStub().PutState(id, assetJSON)
}
// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if assetJSON == nil {
return nil, fmt.Errorf("the asset %s does not exist", id)
}
var asset Asset
err = json.Unmarshal(assetJSON, &asset)
if err != nil {
return nil, err
}
return &asset, nil
}
// UpdateAsset updates an existing asset in the world state with provided parameters.
// Needs an endorsement of current owner Org Peer.
func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, value string, owner string) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
ownerOrg, err := s.getClientOrgId(ctx)
if err != nil {
return err
}
// overwriting original asset with new asset
asset := Asset{
ID: id,
Value: value,
Owner: owner,
OwnerOrg: ownerOrg,
}
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
return ctx.GetStub().PutState(id, assetJSON)
}
// DeleteAsset deletes an given asset from the world state.
//Needs an endorsement of current owner Org Peer.
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
exists, err := s.AssetExists(ctx, id)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("the asset %s does not exist", id)
}
return ctx.GetStub().DelState(id)
}
// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(id)
if err != nil {
return false, fmt.Errorf("failed to read from world state: %v", err)
}
return assetJSON != nil, nil
}
// TransferAsset updates the owner field of asset with given id in world state.
// Needs an endorsement of current owner Org Peer.
// Re-sets the endorsement policy of the assetId Key, such that new owner Org Peer is required to endorse future updates.
func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string, newOwnerOrg string) error {
asset, err := s.ReadAsset(ctx, id)
if err != nil {
return err
}
asset.Owner = newOwner
asset.OwnerOrg = newOwnerOrg
assetJSON, err := json.Marshal(asset)
if err != nil {
return err
}
// Re-Set the endorsement policy of the assetId Key, such that a new owner Org Peer is required to endorse future updates
setStateBasedEndorsement(ctx, 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
// setStateBasedEndorsementNOutOf(ctx, assetId, 1, new String[]{"Org1MSP", "Org2MSP"});
return ctx.GetStub().PutState(id, assetJSON)
}
// Retrieves the client's OrgId (MSPID)
func (s *SmartContract) getClientOrgId(ctx contractapi.TransactionContextInterface) (string, error) {
return ctx.GetClientIdentity().GetMSPID()
}
// Sets an endorsement policy to the assetId Key.
// Enforces that the owner Org must endorse future update transactions for the specified assetId Key.
func setStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, ownerOrgs string) {
var ep KeyEndorsementPolicy
ep.AddOrgs("MEMBER", ownerOrgs)
ctx.GetStub().SetStateValidationParameter(assetId, ep.getPolicy())
}
// Sets an endorsement policy to the assetId Key.
// Enforces that a given number of Orgs (N) out of the specified Orgs must endorse future update transactions for the specified assetId Key.
func setStateBasedEndorsementNOutOf(ctx contractapi.TransactionContextInterface, assetId string, nOrgs int, ownerOrgs []string) {
ctx.GetStub().SetStateValidationParameter(assetId, policy(nOrgs, ownerOrgs))
}
// Create a policy that requires a given number (N) of Org principals signatures out of the provided list of Orgs
func policy(nOrgs int, mspids []string) []byte {
sort.Strings(mspids)
var principals []string
var signPolicy []string
for i := 0; i < len(mspids); i++ {
mspid := mspids[i]
var mspRole MSPRole
mspRole := MSPRole{
mspId,
MSPRole.MSPRoleType.MEMBER}
var MSPPrincipal principals
principal := MSPPrincipal{
fabprotos.common.MSPPrincipal.Classification.ROLE,
fabprotos.common.MSPRole.encode(mspRole).finish()}
principals = append(principals, MspPrincipal.MSPPrincipal.newBuilder().setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE).setPrincipal(MspPrincipal.MSPRole.newBuilder().setMspIdentifier(mspid).setRole(MspPrincipal.MSPRole.MSPRoleType.MEMBER).build().toByteString()).build())
var signedBy SignaturePolicy_SignedBy
signedBy := SignaturePolicy_SignedBy{i}
signPolicy = append(signPolicy, signedBy)
}
// create the policy such that it requires any N signature's from all of the principals provided
var allOf SignaturePolicy_NOutOf
allOf := SignaturePolicy_NOutOf{nOrgs, signPolicies}
var nOutof SignaturePolicy_NOutOf_
noutof := SignaturePolicy_NOutOf_{allOf}
var spe SignaturePolicyEnvelope
spe := SignaturePolicyEnvelope{
version: 0,
rule: noutof,
identities: principals}
return
}