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