github.com/kaituanwang/hyperledger@v2.0.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/comm" 25 "github.com/hyperledger/fabric/core/config" 26 "github.com/hyperledger/fabric/core/scc/cscc" 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 os.IsNotExist(err) || !fi.IsDir() { 125 // No need to try to load MSP from folder which is not available 126 return errors.Errorf("cannot init crypto, folder \"%s\" does not exist", mspMgrConfigDir) 127 } 128 // Check whether localMSPID exists 129 if localMSPID == "" { 130 return errors.New("the local MSP must have an ID") 131 } 132 133 // Init the BCCSP 134 SetBCCSPKeystorePath() 135 bccspConfig := factory.GetDefaultOpts() 136 if config := viper.Get("peer.BCCSP"); config != nil { 137 err = mapstructure.Decode(config, bccspConfig) 138 if err != nil { 139 return errors.WithMessage(err, "could not decode peer BCCSP configuration") 140 } 141 } 142 143 err = mspmgmt.LoadLocalMspWithType(mspMgrConfigDir, bccspConfig, localMSPID, localMSPType) 144 if err != nil { 145 return errors.WithMessagef(err, "error when setting up MSP of type %s from directory %s", localMSPType, mspMgrConfigDir) 146 } 147 148 return nil 149 } 150 151 // SetBCCSPKeystorePath sets the file keystore path for the SW BCCSP provider 152 // to an absolute path relative to the config file 153 func SetBCCSPKeystorePath() { 154 viper.Set("peer.BCCSP.SW.FileKeyStore.KeyStore", 155 config.GetPath("peer.BCCSP.SW.FileKeyStore.KeyStore")) 156 } 157 158 // GetDefaultSigner return a default Signer(Default/PEER) for cli 159 func GetDefaultSigner() (msp.SigningIdentity, error) { 160 signer, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetDefaultSigningIdentity() 161 if err != nil { 162 return nil, errors.WithMessage(err, "error obtaining the default signing identity") 163 } 164 165 return signer, err 166 } 167 168 // Signer defines the interface needed for signing messages 169 type Signer interface { 170 Sign(msg []byte) ([]byte, error) 171 Serialize() ([]byte, error) 172 } 173 174 // GetOrdererEndpointOfChain returns orderer endpoints of given chain 175 func GetOrdererEndpointOfChain(chainID string, signer Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { 176 // query cscc for chain config block 177 invocation := &pb.ChaincodeInvocationSpec{ 178 ChaincodeSpec: &pb.ChaincodeSpec{ 179 Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), 180 ChaincodeId: &pb.ChaincodeID{Name: "cscc"}, 181 Input: &pb.ChaincodeInput{Args: [][]byte{[]byte(cscc.GetConfigBlock), []byte(chainID)}}, 182 }, 183 } 184 185 creator, err := signer.Serialize() 186 if err != nil { 187 return nil, errors.WithMessage(err, "error serializing identity for signer") 188 } 189 190 prop, _, err := protoutil.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator) 191 if err != nil { 192 return nil, errors.WithMessage(err, "error creating GetConfigBlock proposal") 193 } 194 195 signedProp, err := protoutil.GetSignedProposal(prop, signer) 196 if err != nil { 197 return nil, errors.WithMessage(err, "error creating signed GetConfigBlock proposal") 198 } 199 200 proposalResp, err := endorserClient.ProcessProposal(context.Background(), signedProp) 201 if err != nil { 202 return nil, errors.WithMessage(err, "error endorsing GetConfigBlock") 203 } 204 205 if proposalResp == nil { 206 return nil, errors.WithMessage(err, "error nil proposal response") 207 } 208 209 if proposalResp.Response.Status != 0 && proposalResp.Response.Status != 200 { 210 return nil, errors.Errorf("error bad proposal response %d: %s", proposalResp.Response.Status, proposalResp.Response.Message) 211 } 212 213 // parse config block 214 block, err := protoutil.UnmarshalBlock(proposalResp.Response.Payload) 215 if err != nil { 216 return nil, errors.WithMessage(err, "error unmarshaling config block") 217 } 218 219 envelopeConfig, err := protoutil.ExtractEnvelope(block, 0) 220 if err != nil { 221 return nil, errors.WithMessage(err, "error extracting config block envelope") 222 } 223 bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, cryptoProvider) 224 if err != nil { 225 return nil, errors.WithMessage(err, "error loading config block") 226 } 227 228 return bundle.ChannelConfig().OrdererAddresses(), nil 229 } 230 231 // CheckLogLevel checks that a given log level string is valid 232 func CheckLogLevel(level string) error { 233 if !flogging.IsValidLevel(level) { 234 return errors.Errorf("invalid log level provided - %s", level) 235 } 236 return nil 237 } 238 239 func configFromEnv(prefix string) (address, override string, clientConfig comm.ClientConfig, err error) { 240 address = viper.GetString(prefix + ".address") 241 override = viper.GetString(prefix + ".tls.serverhostoverride") 242 clientConfig = comm.ClientConfig{} 243 connTimeout := viper.GetDuration(prefix + ".client.connTimeout") 244 if connTimeout == time.Duration(0) { 245 connTimeout = defaultConnTimeout 246 } 247 clientConfig.Timeout = connTimeout 248 secOpts := comm.SecureOptions{ 249 UseTLS: viper.GetBool(prefix + ".tls.enabled"), 250 RequireClientCert: viper.GetBool(prefix + ".tls.clientAuthRequired")} 251 if secOpts.UseTLS { 252 caPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.rootcert.file")) 253 if res != nil { 254 err = errors.WithMessage(res, 255 fmt.Sprintf("unable to load %s.tls.rootcert.file", prefix)) 256 return 257 } 258 secOpts.ServerRootCAs = [][]byte{caPEM} 259 } 260 if secOpts.RequireClientCert { 261 keyPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientKey.file")) 262 if res != nil { 263 err = errors.WithMessage(res, 264 fmt.Sprintf("unable to load %s.tls.clientKey.file", prefix)) 265 return 266 } 267 secOpts.Key = keyPEM 268 certPEM, res := ioutil.ReadFile(config.GetPath(prefix + ".tls.clientCert.file")) 269 if res != nil { 270 err = errors.WithMessage(res, 271 fmt.Sprintf("unable to load %s.tls.clientCert.file", prefix)) 272 return 273 } 274 secOpts.Certificate = certPEM 275 } 276 clientConfig.SecOpts = secOpts 277 return 278 } 279 280 func InitCmd(cmd *cobra.Command, args []string) { 281 err := InitConfig(CmdRoot) 282 if err != nil { // Handle errors reading the config file 283 mainLogger.Errorf("Fatal error when initializing %s config : %s", CmdRoot, err) 284 os.Exit(1) 285 } 286 287 // read in the legacy logging level settings and, if set, 288 // notify users of the FABRIC_LOGGING_SPEC env variable 289 var loggingLevel string 290 if viper.GetString("logging_level") != "" { 291 loggingLevel = viper.GetString("logging_level") 292 } else { 293 loggingLevel = viper.GetString("logging.level") 294 } 295 if loggingLevel != "" { 296 mainLogger.Warning("CORE_LOGGING_LEVEL is no longer supported, please use the FABRIC_LOGGING_SPEC environment variable") 297 } 298 299 loggingSpec := os.Getenv("FABRIC_LOGGING_SPEC") 300 loggingFormat := os.Getenv("FABRIC_LOGGING_FORMAT") 301 302 flogging.Init(flogging.Config{ 303 Format: loggingFormat, 304 Writer: logOutput, 305 LogSpec: loggingSpec, 306 }) 307 308 // chaincode packaging does not require material from the local MSP 309 if cmd.CommandPath() == "peer lifecycle chaincode package" { 310 mainLogger.Debug("peer lifecycle chaincode package does not need to init crypto") 311 return 312 } 313 314 // Init the MSP 315 var mspMgrConfigDir = config.GetPath("peer.mspConfigPath") 316 var mspID = viper.GetString("peer.localMspId") 317 var mspType = viper.GetString("peer.localMspType") 318 if mspType == "" { 319 mspType = msp.ProviderTypeToString(msp.FABRIC) 320 } 321 err = InitCrypto(mspMgrConfigDir, mspID, mspType) 322 if err != nil { // Handle errors reading the config file 323 mainLogger.Errorf("Cannot run peer because %s", err.Error()) 324 os.Exit(1) 325 } 326 }