fabric-samples/auction-dutch/chaincode-go/smart-contract/utils.go
nikhil550 1cd71fd26a
Add dutch auction sample with auditor (#426)
Signed-off-by: NIKHIL E GUPTA <ngupta@symbridge.com>
2021-05-24 22:01:54 +02:00

205 lines
5.6 KiB
Go

/*
SPDX-License-Identifier: Apache-2.0
*/
package auction
import (
"encoding/base64"
"fmt"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/msp"
)
func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) {
b64ID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return "", fmt.Errorf("Failed to read clientID: %v", err)
}
decodeID, err := base64.StdEncoding.DecodeString(b64ID)
if err != nil {
return "", fmt.Errorf("failed to base64 decode clientID: %v", err)
}
return string(decodeID), nil
}
// getCollectionName is an internal helper function to get collection of submitting client identity.
func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) {
// Get the MSP ID of submitting client identity
clientMSPID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return "", fmt.Errorf("failed to get verified MSPID: %v", err)
}
// Create the collection name
orgCollection := "_implicit_org_" + clientMSPID
return orgCollection, nil
}
// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id.
func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error {
clientMSPID, err := ctx.GetClientIdentity().GetMSPID()
if err != nil {
return fmt.Errorf("failed getting the client's MSPID: %v", err)
}
peerMSPID, err := shim.GetMSPID()
if err != nil {
return fmt.Errorf("failed getting the peer's MSPID: %v", err)
}
if clientMSPID != peerMSPID {
return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID)
}
return nil
}
func contains(sli []string, str string) bool {
for _, a := range sli {
if a == str {
return true
}
}
return false
}
func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, mspids []string, auditor bool) error {
principals := make([]*msp.MSPPrincipal, len(mspids))
participantSigsPolicy := make([]*common.SignaturePolicy, len(mspids))
for i, id := range mspids {
principal, err := proto.Marshal(
&msp.MSPRole{
Role: msp.MSPRole_PEER,
MspIdentifier: id,
},
)
if err != nil {
return err
}
principals[i] = &msp.MSPPrincipal{
PrincipalClassification: msp.MSPPrincipal_ROLE,
Principal: principal,
}
participantSigsPolicy[i] = &common.SignaturePolicy{
Type: &common.SignaturePolicy_SignedBy{
SignedBy: int32(i),
},
}
}
if auditor == false {
// create the defalt policy for an auction without an auditor
policy := &common.SignaturePolicyEnvelope{
Version: 0,
Rule: &common.SignaturePolicy{
Type: &common.SignaturePolicy_NOutOf_{
NOutOf: &common.SignaturePolicy_NOutOf{
N: int32(len(mspids)),
Rules: participantSigsPolicy,
},
},
},
Identities: principals,
}
spBytes, err := proto.Marshal(policy)
if err != nil {
return err
}
err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes)
if err != nil {
return fmt.Errorf("failed to set validation parameter on auction: %v", err)
}
} else {
// create the defalt policy for an auction with an auditor
// create the auditor identity and signature policy
auditorMSP, err := proto.Marshal(
&msp.MSPRole{
Role: msp.MSPRole_PEER,
MspIdentifier: "Org3MSP",
},
)
if err != nil {
return err
}
principals = append(principals, &msp.MSPPrincipal{
PrincipalClassification: msp.MSPPrincipal_ROLE,
Principal: auditorMSP,
},
)
// Create the policies in case the auditor is needed. In this case, an
// auditor and 1 participant can update the auction.
auditorPolicies := make([]*common.SignaturePolicy, 2)
auditorPolicies[0] = &common.SignaturePolicy{
Type: &common.SignaturePolicy_SignedBy{
SignedBy: int32(len(principals) - 1),
},
}
auditorPolicies[1] = &common.SignaturePolicy{
Type: &common.SignaturePolicy_NOutOf_{
NOutOf: &common.SignaturePolicy_NOutOf{
N: 1,
Rules: participantSigsPolicy,
},
},
}
// For two organizations, the auditor policy below is equivilent to
// AND(auditor, OR(Org1, Org2))
policies := make([]*common.SignaturePolicy, 2)
policies[0] = &common.SignaturePolicy{
Type: &common.SignaturePolicy_NOutOf_{
NOutOf: &common.SignaturePolicy_NOutOf{
N: 2,
Rules: auditorPolicies,
},
},
}
// Participants can also update the auction without an auditor
policies[1] = &common.SignaturePolicy{
Type: &common.SignaturePolicy_NOutOf_{
NOutOf: &common.SignaturePolicy_NOutOf{
N: int32(len(mspids)),
Rules: participantSigsPolicy,
},
},
}
// Either the auditor policy or the participant policy can update
// the auction. For example, for two organizations, the full policy would be
// equivilent to OR(AND(Org1, Org2),AND(auditor, OR(Org1, Org2)))
policy := &common.SignaturePolicyEnvelope{
Version: 0,
Rule: &common.SignaturePolicy{
Type: &common.SignaturePolicy_NOutOf_{
NOutOf: &common.SignaturePolicy_NOutOf{
N: 1,
Rules: policies,
},
},
},
Identities: principals,
}
spBytes, err := proto.Marshal(policy)
if err != nil {
return err
}
err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes)
if err != nil {
return fmt.Errorf("failed to set validation parameter on auction: %v", err)
}
}
return nil
}