forked from tw-bc-group/fabric
-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.go
327 lines (281 loc) · 11.2 KB
/
common.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package common
import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"os"
"strings"
"time"
pcommon "github.com/hyperledger/fabric-protos-go/common"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/core/config"
"github.com/hyperledger/fabric/core/scc/cscc"
"github.com/hyperledger/fabric/internal/pkg/comm"
"github.com/hyperledger/fabric/msp"
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/protoutil"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// UndefinedParamValue defines what undefined parameters in the command line will initialise to
const UndefinedParamValue = ""
const CmdRoot = "core"
var mainLogger = flogging.MustGetLogger("main")
var logOutput = os.Stderr
var (
defaultConnTimeout = 3 * time.Second
// These function variables (xyzFnc) can be used to invoke corresponding xyz function
// this will allow the invoking packages to mock these functions in their unit test cases
// GetEndorserClientFnc is a function that returns a new endorser client connection
// to the provided peer address using the TLS root cert file,
// by default it is set to GetEndorserClient function
GetEndorserClientFnc func(address, tlsRootCertFile string) (pb.EndorserClient, error)
// GetPeerDeliverClientFnc is a function that returns a new deliver client connection
// to the provided peer address using the TLS root cert file,
// by default it is set to GetDeliverClient function
GetPeerDeliverClientFnc func(address, tlsRootCertFile string) (pb.DeliverClient, error)
// GetDeliverClientFnc is a function that returns a new deliver client connection
// to the provided peer address using the TLS root cert file,
// by default it is set to GetDeliverClient function
GetDeliverClientFnc func(address, tlsRootCertFile string) (pb.Deliver_DeliverClient, error)
// GetDefaultSignerFnc is a function that returns a default Signer(Default/PERR)
// by default it is set to GetDefaultSigner function
GetDefaultSignerFnc func() (msp.SigningIdentity, error)
// GetBroadcastClientFnc returns an instance of the BroadcastClient interface
// by default it is set to GetBroadcastClient function
GetBroadcastClientFnc func() (BroadcastClient, error)
// GetOrdererEndpointOfChainFnc returns orderer endpoints of given chain
// by default it is set to GetOrdererEndpointOfChain function
GetOrdererEndpointOfChainFnc func(chainID string, signer Signer,
endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error)
// GetCertificateFnc is a function that returns the client TLS certificate
GetCertificateFnc func() (tls.Certificate, error)
)
type CommonClient struct {
*comm.GRPCClient
Address string
sn string
}
func init() {
GetEndorserClientFnc = GetEndorserClient
GetDefaultSignerFnc = GetDefaultSigner
GetBroadcastClientFnc = GetBroadcastClient
GetOrdererEndpointOfChainFnc = GetOrdererEndpointOfChain
GetDeliverClientFnc = GetDeliverClient
GetPeerDeliverClientFnc = GetPeerDeliverClient
GetCertificateFnc = GetCertificate
}
// InitConfig initializes viper config
func InitConfig(cmdRoot string) error {
err := config.InitViper(nil, cmdRoot)
if err != nil {
return err
}
err = viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
// The version of Viper we use claims the config type isn't supported when in fact the file hasn't been found
// Display a more helpful message to avoid confusing the user.
if strings.Contains(fmt.Sprint(err), "Unsupported Config Type") {
return errors.New(fmt.Sprintf("Could not find config file. "+
"Please make sure that FABRIC_CFG_PATH is set to a path "+
"which contains %s.yaml", cmdRoot))
} else {
return errors.WithMessagef(err, "error when reading %s config file", cmdRoot)
}
}
return nil
}
// InitCrypto initializes crypto for this peer
func InitCrypto(mspMgrConfigDir, localMSPID, localMSPType string) error {
// Check whether msp folder exists
fi, err := os.Stat(mspMgrConfigDir)
if err != nil {
return errors.Errorf("cannot init crypto, specified path \"%s\" does not exist or cannot be accessed: %v", mspMgrConfigDir, err)
} else if !fi.IsDir() {
return errors.Errorf("cannot init crypto, specified path \"%s\" is not a directory", mspMgrConfigDir)
}
// Check whether localMSPID exists
if localMSPID == "" {
return errors.New("the local MSP must have an ID")
}
// Init the BCCSP
SetBCCSPKeystorePath()
bccspConfig := factory.GetDefaultOpts()
if config := viper.Get("peer.BCCSP"); config != nil {
err = mapstructure.Decode(config, bccspConfig)
if err != nil {
return errors.WithMessage(err, "could not decode peer BCCSP configuration")
}
}
err = mspmgmt.LoadLocalMspWithType(mspMgrConfigDir, bccspConfig, localMSPID, localMSPType)
if err != nil {
return errors.WithMessagef(err, "error when setting up MSP of type %s from directory %s", localMSPType, mspMgrConfigDir)
}
return nil
}
// SetBCCSPKeystorePath sets the file keystore path for the SW BCCSP provider
// to an absolute path relative to the config file
func SetBCCSPKeystorePath() {
viper.Set("peer.BCCSP.SW.FileKeyStore.KeyStore",
config.GetPath("peer.BCCSP.SW.FileKeyStore.KeyStore"))
}
// GetDefaultSigner return a default Signer(Default/PEER) for cli
func GetDefaultSigner() (msp.SigningIdentity, error) {
signer, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetDefaultSigningIdentity()
if err != nil {
return nil, errors.WithMessage(err, "error obtaining the default signing identity")
}
return signer, err
}
// Signer defines the interface needed for signing messages
type Signer interface {
Sign(msg []byte) ([]byte, error)
Serialize() ([]byte, error)
}
// GetOrdererEndpointOfChain returns orderer endpoints of given chain
func GetOrdererEndpointOfChain(chainID string, signer Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) {
// query cscc for chain config block
invocation := &pb.ChaincodeInvocationSpec{
ChaincodeSpec: &pb.ChaincodeSpec{
Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]),
ChaincodeId: &pb.ChaincodeID{Name: "cscc"},
Input: &pb.ChaincodeInput{Args: [][]byte{[]byte(cscc.GetConfigBlock), []byte(chainID)}},
},
}
creator, err := signer.Serialize()
if err != nil {
return nil, errors.WithMessage(err, "error serializing identity for signer")
}
prop, _, err := protoutil.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator)
if err != nil {
return nil, errors.WithMessage(err, "error creating GetConfigBlock proposal")
}
signedProp, err := protoutil.GetSignedProposal(prop, signer)
if err != nil {
return nil, errors.WithMessage(err, "error creating signed GetConfigBlock proposal")
}
proposalResp, err := endorserClient.ProcessProposal(context.Background(), signedProp)
if err != nil {
return nil, errors.WithMessage(err, "error endorsing GetConfigBlock")
}
if proposalResp == nil {
return nil, errors.WithMessage(err, "error nil proposal response")
}
if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 {
return nil, errors.Errorf("error bad proposal response %d: %s", proposalResp.Response.Status, proposalResp.Response.Message)
}
// parse config block
block, err := protoutil.UnmarshalBlock(proposalResp.Response.Payload)
if err != nil {
return nil, errors.WithMessage(err, "error unmarshaling config block")
}
envelopeConfig, err := protoutil.ExtractEnvelope(block, 0)
if err != nil {
return nil, errors.WithMessage(err, "error extracting config block envelope")
}
bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, cryptoProvider)
if err != nil {
return nil, errors.WithMessage(err, "error loading config block")
}
return bundle.ChannelConfig().OrdererAddresses(), nil
}
// CheckLogLevel checks that a given log level string is valid
func CheckLogLevel(level string) error {
if !flogging.IsValidLevel(level) {
return errors.Errorf("invalid log level provided - %s", level)
}
return nil
}
func configFromEnv(prefix string) (address, override string, clientConfig comm.ClientConfig, err error) {
address = viper.GetString(prefix + ".address")
override = viper.GetString(prefix + ".tls.serverhostoverride")
clientConfig = comm.ClientConfig{}
connTimeout := viper.GetDuration(prefix + ".client.connTimeout")
if connTimeout == time.Duration(0) {
connTimeout = defaultConnTimeout
}
clientConfig.Timeout = connTimeout
secOpts := comm.SecureOptions{
UseTLS: viper.GetBool(prefix + ".tls.enabled"),
RequireClientCert: viper.GetBool(prefix + ".tls.clientAuthRequired")}
if secOpts.UseTLS {
caPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.rootcert.file"))
if res != nil {
err = errors.WithMessage(res,
fmt.Sprintf("unable to load %s.tls.rootcert.file", prefix))
return
}
secOpts.ServerRootCAs = [][]byte{caPEM}
}
if secOpts.RequireClientCert {
keyPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientKey.file"))
if res != nil {
err = errors.WithMessage(res,
fmt.Sprintf("unable to load %s.tls.clientKey.file", prefix))
return
}
secOpts.Key = keyPEM
certPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientCert.file"))
if res != nil {
err = errors.WithMessage(res,
fmt.Sprintf("unable to load %s.tls.clientCert.file", prefix))
return
}
secOpts.Certificate = certPEM
}
clientConfig.SecOpts = secOpts
return
}
func InitCmd(cmd *cobra.Command, args []string) {
err := InitConfig(CmdRoot)
if err != nil { // Handle errors reading the config file
mainLogger.Errorf("Fatal error when initializing %s config : %s", CmdRoot, err)
os.Exit(1)
}
// read in the legacy logging level settings and, if set,
// notify users of the FABRIC_LOGGING_SPEC env variable
var loggingLevel string
if viper.GetString("logging_level") != "" {
loggingLevel = viper.GetString("logging_level")
} else {
loggingLevel = viper.GetString("logging.level")
}
if loggingLevel != "" {
mainLogger.Warning("CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable")
}
loggingSpec := os.Getenv("FABRIC_LOGGING_SPEC")
loggingFormat := os.Getenv("FABRIC_LOGGING_FORMAT")
flogging.Init(flogging.Config{
Format: loggingFormat,
Writer: logOutput,
LogSpec: loggingSpec,
})
// chaincode packaging does not require material from the local MSP
if cmd.CommandPath() == "peer lifecycle chaincode package" {
mainLogger.Debug("peer lifecycle chaincode package does not need to init crypto")
return
}
// Init the MSP
var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
var mspID = viper.GetString("peer.localMspId")
var mspType = viper.GetString("peer.localMspType")
if mspType == "" {
mspType = msp.ProviderTypeToString(msp.FABRIC)
}
err = InitCrypto(mspMgrConfigDir, mspID, mspType)
if err != nil { // Handle errors reading the config file
mainLogger.Errorf("Cannot run peer because %s", err.Error())
os.Exit(1)
}
}