github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/internal/peer/lifecycle/chaincode/queryapproved.go (about) 1 /* 2 Copyright Hitachi America, Ltd. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "context" 11 "fmt" 12 "io" 13 "os" 14 "strings" 15 16 "github.com/golang/protobuf/proto" 17 cb "github.com/hyperledger/fabric-protos-go/common" 18 pb "github.com/hyperledger/fabric-protos-go/peer" 19 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 20 "github.com/osdi23p228/fabric/bccsp" 21 "github.com/osdi23p228/fabric/protoutil" 22 "github.com/pkg/errors" 23 "github.com/spf13/cobra" 24 "github.com/spf13/viper" 25 ) 26 27 // ApprovedQuerier holds the dependencies needed to query 28 // the approved chaincode definition for the organization 29 type ApprovedQuerier struct { 30 Command *cobra.Command 31 EndorserClient EndorserClient 32 Input *ApprovedQueryInput 33 Signer Signer 34 Writer io.Writer 35 } 36 37 type ApprovedQueryInput struct { 38 ChannelID string 39 Name string 40 Sequence int64 41 OutputFormat string 42 } 43 44 // QueryApprovedCmd returns the cobra command for 45 // querying the approved chaincode definition for the organization 46 func QueryApprovedCmd(a *ApprovedQuerier, cryptoProvider bccsp.BCCSP) *cobra.Command { 47 chaincodeQueryApprovedCmd := &cobra.Command{ 48 Use: "queryapproved", 49 Short: "Query an org's approved chaincode definition from its peer.", 50 Long: "Query an organization's approved chaincode definition from its peer.", 51 RunE: func(cmd *cobra.Command, args []string) error { 52 if a == nil { 53 ccInput := &ClientConnectionsInput{ 54 CommandName: cmd.Name(), 55 EndorserRequired: true, 56 ChannelID: channelID, 57 PeerAddresses: peerAddresses, 58 TLSRootCertFiles: tlsRootCertFiles, 59 ConnectionProfilePath: connectionProfilePath, 60 TLSEnabled: viper.GetBool("peer.tls.enabled"), 61 } 62 63 cc, err := NewClientConnections(ccInput, cryptoProvider) 64 if err != nil { 65 return err 66 } 67 68 aqInput := &ApprovedQueryInput{ 69 ChannelID: channelID, 70 Name: chaincodeName, 71 Sequence: int64(sequence), 72 OutputFormat: output, 73 } 74 75 a = &ApprovedQuerier{ 76 Command: cmd, 77 EndorserClient: cc.EndorserClients[0], 78 Input: aqInput, 79 Signer: cc.Signer, 80 Writer: os.Stdout, 81 } 82 } 83 return a.Query() 84 }, 85 } 86 flagList := []string{ 87 "channelID", 88 "name", 89 "sequence", 90 "peerAddresses", 91 "tlsRootCertFiles", 92 "connectionProfile", 93 "output", 94 } 95 attachFlags(chaincodeQueryApprovedCmd, flagList) 96 97 return chaincodeQueryApprovedCmd 98 } 99 100 // Query returns the approved chaincode definition 101 // for a given channel and chaincode name 102 func (a *ApprovedQuerier) Query() error { 103 if a.Command != nil { 104 // Parsing of the command line is done so silence cmd usage 105 a.Command.SilenceUsage = true 106 } 107 108 err := a.validateInput() 109 if err != nil { 110 return err 111 } 112 113 proposal, err := a.createProposal() 114 if err != nil { 115 return errors.WithMessage(err, "failed to create proposal") 116 } 117 118 signedProposal, err := signProposal(proposal, a.Signer) 119 if err != nil { 120 return errors.WithMessage(err, "failed to create signed proposal") 121 } 122 123 proposalResponse, err := a.EndorserClient.ProcessProposal(context.Background(), signedProposal) 124 if err != nil { 125 return errors.WithMessage(err, "failed to endorse proposal") 126 } 127 128 if proposalResponse == nil { 129 return errors.New("received nil proposal response") 130 } 131 132 if proposalResponse.Response == nil { 133 return errors.New("received proposal response with nil response") 134 } 135 136 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 137 return errors.Errorf("query failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 138 } 139 140 if strings.ToLower(a.Input.OutputFormat) == "json" { 141 return printResponseAsJSON(proposalResponse, &lb.QueryApprovedChaincodeDefinitionResult{}, a.Writer) 142 } 143 return a.printResponse(proposalResponse) 144 } 145 146 // printResponse prints the information included in the response 147 // from the server as human readable plain-text. 148 func (a *ApprovedQuerier) printResponse(proposalResponse *pb.ProposalResponse) error { 149 result := &lb.QueryApprovedChaincodeDefinitionResult{} 150 err := proto.Unmarshal(proposalResponse.Response.Payload, result) 151 if err != nil { 152 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 153 } 154 fmt.Fprintf(a.Writer, "Approved chaincode definition for chaincode '%s' on channel '%s':\n", a.Input.Name, a.Input.ChannelID) 155 156 var packageID string 157 if result.Source != nil { 158 switch source := result.Source.Type.(type) { 159 case *lb.ChaincodeSource_LocalPackage: 160 packageID = source.LocalPackage.PackageId 161 case *lb.ChaincodeSource_Unavailable_: 162 } 163 } 164 fmt.Fprintf(a.Writer, "sequence: %d, version: %s, init-required: %t, package-id: %s, endorsement plugin: %s, validation plugin: %s\n", 165 result.Sequence, result.Version, result.InitRequired, packageID, result.EndorsementPlugin, result.ValidationPlugin) 166 return nil 167 } 168 169 func (a *ApprovedQuerier) validateInput() error { 170 if a.Input.ChannelID == "" { 171 return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") 172 } 173 174 if a.Input.Name == "" { 175 return errors.New("The required parameter 'name' is empty. Rerun the command with -n flag") 176 } 177 178 return nil 179 } 180 181 func (a *ApprovedQuerier) createProposal() (*pb.Proposal, error) { 182 var function string 183 var args proto.Message 184 185 function = "QueryApprovedChaincodeDefinition" 186 args = &lb.QueryApprovedChaincodeDefinitionArgs{ 187 Name: a.Input.Name, 188 Sequence: a.Input.Sequence, 189 } 190 191 argsBytes, err := proto.Marshal(args) 192 if err != nil { 193 return nil, errors.Wrap(err, "failed to marshal args") 194 } 195 ccInput := &pb.ChaincodeInput{Args: [][]byte{[]byte(function), argsBytes}} 196 197 cis := &pb.ChaincodeInvocationSpec{ 198 ChaincodeSpec: &pb.ChaincodeSpec{ 199 ChaincodeId: &pb.ChaincodeID{Name: lifecycleName}, 200 Input: ccInput, 201 }, 202 } 203 204 signerSerialized, err := a.Signer.Serialize() 205 if err != nil { 206 return nil, errors.WithMessage(err, "failed to serialize identity") 207 } 208 209 proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, a.Input.ChannelID, cis, signerSerialized) 210 if err != nil { 211 return nil, errors.WithMessage(err, "failed to create ChaincodeInvocationSpec proposal") 212 } 213 214 return proposal, nil 215 }