/
query.go
132 lines (107 loc) · 3.24 KB
/
query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package queryinstalled
import (
"context"
"errors"
"fmt"
"github.com/bestbeforetoday/fabric-admin/internal/common"
"github.com/bestbeforetoday/fabric-admin/internal/proposal"
"github.com/bestbeforetoday/fabric-admin/pkg/identity"
"github.com/hyperledger/fabric-protos-go-apiv2/peer"
"github.com/hyperledger/fabric-protos-go-apiv2/peer/lifecycle"
"google.golang.org/grpc"
"google.golang.org/protobuf/proto"
)
const queryInstalledTransactionName = "QueryInstalledChaincodes"
func Query(ctx context.Context, signingID identity.SigningIdentity, options ...Option) (*lifecycle.QueryInstalledChaincodesResult, error) {
installCommand := &command{
signingID: signingID,
}
if err := common.ApplyOptions(installCommand, options...); err != nil {
return nil, err
}
return installCommand.run(ctx)
}
type command struct {
signingID identity.SigningIdentity
grpcClient peer.EndorserClient
grpcOptions []grpc.CallOption
}
func (c *command) run(ctx context.Context) (*lifecycle.QueryInstalledChaincodesResult, error) {
if err := c.validate(); err != nil {
return nil, err
}
signedProposal, err := c.signedProposal()
if err != nil {
return nil, err
}
proposalResponse, err := c.grpcClient.ProcessProposal(ctx, signedProposal, c.grpcOptions...)
if err != nil {
return nil, err
}
if err = proposal.CheckSuccessfulResponse(proposalResponse); err != nil {
return nil, err
}
result := &lifecycle.QueryInstalledChaincodesResult{}
if err = proto.Unmarshal(proposalResponse.GetResponse().GetPayload(), result); err != nil {
return nil, fmt.Errorf("failed to deserialize query installed chaincode result: %w", err)
}
return result, nil
}
func (c *command) validate() error {
if c.grpcClient == nil {
return errors.New("no gRPC client supplied")
}
return nil
}
func (c *command) signedProposal() (*peer.SignedProposal, error) {
argBytes, err := c.queryInstalledChaincodesArgsBytes()
if err != nil {
return nil, err
}
proposal, err := proposal.New(
c.signingID,
common.LifecycleChaincodeName,
queryInstalledTransactionName,
proposal.WithBytesArguments(argBytes),
)
if err != nil {
return nil, err
}
proposalBytes, err := proto.Marshal(proposal)
if err != nil {
return nil, err
}
signature, err := c.signingID.Sign(proposalBytes)
if err != nil {
return nil, err
}
signedProposal := &peer.SignedProposal{
ProposalBytes: proposalBytes,
Signature: signature,
}
return signedProposal, nil
}
func (c *command) queryInstalledChaincodesArgsBytes() ([]byte, error) {
installArgs := &lifecycle.QueryInstalledChaincodesArgs{}
return proto.Marshal(installArgs)
}
type Option = func(*command) error
// WithClientConnection uses the supplied gRPC client connection. This should be shared by all commands
// connecting to the same network node.
func WithClientConnection(clientConnection grpc.ClientConnInterface) Option {
return func(c *command) error {
c.grpcClient = peer.NewEndorserClient(clientConnection)
return nil
}
}
// WithCallOptions specifies the gRPC call options to be used.
func WithCallOptions(options ...grpc.CallOption) Option {
return func(c *command) error {
c.grpcOptions = append(c.grpcOptions, options...)
return nil
}
}