hyperledger / fabric-admin-sdk

Hyperledger Fabric admin SDK
Apache License 2.0
31 stars 19 forks source link

need a function to translate SignaturePolicyEnvelope to human readable expression #127

Closed 1gezhanghao closed 1 year ago

1gezhanghao commented 1 year ago

there is a func signaturePolicyEnvelopeFromString(policy string) (*cb.SignaturePolicyEnvelope, error) https://github.com/hyperledger/fabric-admin-sdk/blob/main/pkg/chaincode/signaturepolicy.go#L287 which can translate a SignaturePolicyExpression to cb.SignaturePolicyEnvelope

eg: AND('Org1MSP.peer','Org2MSP.peer') be translate to cb.SignaturePolicyEnvelope, the json as follows

{
    "rule": {
        "Type": {
            "NOutOf": {
                "n": 2,
                "rules": [
                    {
                        "Type": {
                            "SignedBy": 0
                        }
                    },
                    {
                        "Type": {
                            "SignedBy": 1
                        }
                    }
                ]
            }
        }
    },
    "identities": [
        {
            "principal": "CgdPcmcxTVNQEAM="
        },
        {
            "principal": "CgdPcmcyTVNQEAM="
        }
    ]
}

now i need a function SignaturePolicyEnvelopeToString(*cb.SignaturePolicyEnvelope)(policy string,err error) which translate cb.SignaturePolicyEnvelope back to the human readable SignaturePolicyExpression so that people can read SignaturePolicy info from commitedCC

1gezhanghao commented 1 year ago

BTW, there is a packageID needed when commit a chaincode

        chaincodeDef := &chaincode.Definition{                                                                                                                                    
                ChannelName:       rq.Channel,                                                                                                                                    
                PackageID:         rq.PackageID,                                                                                                                                  
                Name:              rq.Name,                                                                                                                                       
                Version:           rq.Version,                                                                                                                                    
                EndorsementPlugin: "",                                                                                                                                            
                ValidationPlugin:  "",                                                                                                                                            
                Sequence:          rq.Sequence,                                                                                                                                   
                ApplicationPolicy: applicationPolicy,                                                                                                                             
                InitRequired:      rq.InitRequired,                                                                                                                               
                Collections:       nil,                                                                                                                                           
        }

but, there is no packageID when query commited chaincode

type QueryChaincodeDefinitionsResult_ChaincodeDefinition struct {                                                                                                                 
        state         protoimpl.MessageState                                                                                                                                      
        sizeCache     protoimpl.SizeCache                                                                                                                                         
        unknownFields protoimpl.UnknownFields                                                                                                                                     

        Name                string                        `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`                                                         
        Sequence            int64                         `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"`                                                
        Version             string                        `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`                                                   
        EndorsementPlugin   string                        `protobuf:"bytes,4,opt,name=endorsement_plugin,json=endorsementPlugin,proto3" json:"endorsement_plugin,omitempty"`      
        ValidationPlugin    string                        `protobuf:"bytes,5,opt,name=validation_plugin,json=validationPlugin,proto3" json:"validation_plugin,omitempty"`         
        ValidationParameter []byte                        `protobuf:"bytes,6,opt,name=validation_parameter,json=validationParameter,proto3" json:"validation_parameter,omitempty"`
        Collections         *peer.CollectionConfigPackage `protobuf:"bytes,7,opt,name=collections,proto3" json:"collections,omitempty"`                                           
        InitRequired        bool                          `protobuf:"varint,8,opt,name=init_required,json=initRequired,proto3" json:"init_required,omitempty"`                    
}

how people figure out which packageID the commitCC used?

bestbeforetoday commented 1 year ago

BTW, there is a packageID needed when commit a chaincode

The package ID is not required and not used for chaincode commit:

https://github.com/hyperledger/fabric-admin-sdk/blob/56a77d5313c070137745da342d8aaccca387426e/pkg/chaincode/commit.go#L27-L36

It appears as if the package ID is required because the chaincode definition is reused by all the chaincode operations. For most (if not all) of the chaincode operations, there are redundant elements in that chaincode definition.

Do you think it would be clearer if each function took a specific type that defined only the properties relevant to that function, or is it more convenient to be able to use a single chaincode definition for all steps in the chaincode lifecycle?

SamYuan1990 commented 1 year ago

I am open to any suggestion as we currently keep same with https://hyperledger-fabric.readthedocs.io/en/release-2.5/policies.html?highlight=SignaturePolicy#constructing-a-signaturepolicy

1gezhanghao commented 1 year ago

BTW, there is a packageID needed when commit a chaincode

The package ID is not required and not used for chaincode commit:

https://github.com/hyperledger/fabric-admin-sdk/blob/56a77d5313c070137745da342d8aaccca387426e/pkg/chaincode/commit.go#L27-L36

It appears as if the package ID is required because the chaincode definition is reused by all the chaincode operations. For most (if not all) of the chaincode operations, there are redundant elements in that chaincode definition.

Do you think it would be clearer if each function took a specific type that defined only the properties relevant to that function, or is it more convenient to be able to use a single chaincode definition for all steps in the chaincode lifecycle?

I get this, the packageid is in approvedCC that corresponding to commitedCC It is more convenient to use a single chaincode definition request for all steps in the chaincode lifecycle. in the same way, if there is a single chaincode definition result for all steps, will help to view information for all steps in the chaincode lifecycle.

1gezhanghao commented 1 year ago

I'm write an implementation for this, hope that helps, code as follows

package main                                                                                                                                                                      

import (                                                                                                                                                                          
        "bytes"                                                                                                                                                                   
        "encoding/json"                                                                                                                                                           
        "fmt"                                                                                                                                                                     
        "log"                                                                                                                                                                     
        "strings"                                                                                                                                                                 

        "github.com/hyperledger/fabric-admin-sdk/pkg/chaincode"                                                                                                                   
        cb "github.com/hyperledger/fabric-protos-go-apiv2/common"                                                                                                                 
)                                                                                                                                                                                 

func main() {                                                                                                                                                                     
        log.SetFlags(log.Lshortfile)                                                                                                                                              

        expression := `OR('Org3MSP.peer','Org1MSP.admin','Org2MSP.member')`                                                                                                  
        expression = `AND('Org3MSP.peer','Org1MSP.admin','Org2MSP.member')`                                                                                                       
        expression = `AND('Org3MSP.peer',OR('Org1MSP.admin','Org2MSP.member'))`                                                                                                   
        expression = `OutOf(2,'Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')`                                                                                 
        log.Println(expression)                                                                                                                                                   

        applicationPolicy, err := chaincode.NewApplicationPolicy(expression, "")                                                                                                  
        if err != nil {                                                                                                                                                           
                panic(err)                                                                                                                                                        
        }                                                                                                                                                                         

        policy := applicationPolicy.GetSignaturePolicy()                                                                                                                          

        body, _ := json.MarshalIndent(policy, "", "    ")                                                                                                                         
        log.Println(string(body))                                                                                                                                                 

        humanReadablePolicy := SignaturePolicyEnvelopeToString(policy)                                                                                                            
        log.Println(humanReadablePolicy)                                                                                                                                          
} 

//translate SignaturePolicyEnvelope to human readable expression                                                                                                                  
func SignaturePolicyEnvelopeToString(policy *cb.SignaturePolicyEnvelope) string {                                                                                                 
        ids := []string{}                                                                                                                                                         
        for _, id := range policy.Identities {    
                var mspRole msp.MSPRole                                                                                                                                           
                proto.Unmarshal(id.Principal, &mspRole)                                                                                                                           
                mspid := mspRole.MspIdentifier + "." + msp.MSPRole_MSPRoleType_name[int32(mspRole.Role)]                                                                                                                                                                                                                
                ids = append(ids, mspid)                                                                                                                                   
        }                                                                                                                                                                         

        var buf bytes.Buffer                                                                                                                                                      
        policyParse(policy.Rule.Type, ids, &buf)                                                                                                                                  
        return buf.String()                                                                                                                                                       
}                                                                                                                                                                                 

func policyParse(t any, ids []string, buf *bytes.Buffer) {                                                                                                                        
        p1, ok := t.(*cb.SignaturePolicy_SignedBy)                                                                                                                                
        if ok {                                                                                                                                                                   
                buf.WriteString("'")                                                                                                                                              
                buf.WriteString(ids[p1.SignedBy])                                                                                                                                 
                buf.WriteString("'")                                                                                                                                              
                return                                                                                                                                                            
        }                                                                                                                                                                         

        p2, ok := t.(*cb.SignaturePolicy_NOutOf_)                                                                                                                                 
        if ok {                                                                                                                                                                   
                l := len(p2.NOutOf.Rules)                                                                                                                                         
                n := int32(l)                                                                                                                                                     

                if p2.NOutOf.N == n {                                                                                                                                             
                        buf.WriteString("AND(")                                                                                                                                   
                } else if p2.NOutOf.N == 1 {                                                                                                                                      
                        buf.WriteString("OR(")                                                                                                                                    
                } else {                                                                                                                                                          
                        buf.WriteString("OutOf(")                                                                                                                                 
                        buf.WriteString(fmt.Sprint(p2.NOutOf.N))                                                                                                                  
                        buf.WriteString(",")                                                                                                                                      
                }                                                                                                                                                                 
                for i, r := range p2.NOutOf.Rules {                                                                                                                               
                        policyParse(r.Type, ids, buf)                                                                                                                             
                        if i == len(p2.NOutOf.Rules)-1 {                                                                                                                          
                                buf.WriteString(")")                                                                                                                              
                        } else {                                                                                                                                                  
                                buf.WriteString(",")                                                                                                                              
                        }                                                                                                                                                         
                }                                                                                                                                                                 
        }                                                                                                                                                                         

}