github.com/true-sqn/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  }