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