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  }