Closed 1gezhanghao closed 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?
BTW, there is a packageID needed when commit a chaincode
The package ID is not required and not used for chaincode commit:
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 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
BTW, there is a packageID needed when commit a chaincode
The package ID is not required and not used for chaincode commit:
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.
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(",")
}
}
}
}
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.SignaturePolicyEnvelopeeg:
AND('Org1MSP.peer','Org2MSP.peer')
be translate to cb.SignaturePolicyEnvelope, the json as followsnow 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