github.com/lzy4123/fabric@v2.1.1+incompatible/discovery/support/config/support.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package config
     8  
     9  import (
    10  	"fmt"
    11  	"net"
    12  	"strconv"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"github.com/hyperledger/fabric-protos-go/common"
    16  	"github.com/hyperledger/fabric-protos-go/discovery"
    17  	"github.com/hyperledger/fabric-protos-go/msp"
    18  	"github.com/hyperledger/fabric/common/channelconfig"
    19  	"github.com/hyperledger/fabric/common/flogging"
    20  	mspconstants "github.com/hyperledger/fabric/msp"
    21  	"github.com/pkg/errors"
    22  )
    23  
    24  var logger = flogging.MustGetLogger("discovery.config")
    25  
    26  // CurrentConfigBlockGetter enables to fetch the last config block
    27  type CurrentConfigBlockGetter interface {
    28  	// GetCurrConfigBlock returns the current config block for the given channel
    29  	GetCurrConfigBlock(channel string) *common.Block
    30  }
    31  
    32  // CurrentConfigBlockGetterFunc enables to fetch the last config block
    33  type CurrentConfigBlockGetterFunc func(channel string) *common.Block
    34  
    35  // CurrentConfigBlockGetterFunc enables to fetch the last config block
    36  func (f CurrentConfigBlockGetterFunc) GetCurrConfigBlock(channel string) *common.Block {
    37  	return f(channel)
    38  }
    39  
    40  // DiscoverySupport implements support that is used for service discovery
    41  // that is related to configuration
    42  type DiscoverySupport struct {
    43  	CurrentConfigBlockGetter
    44  }
    45  
    46  // NewDiscoverySupport creates a new DiscoverySupport
    47  func NewDiscoverySupport(getLastConfigBlock CurrentConfigBlockGetter) *DiscoverySupport {
    48  	return &DiscoverySupport{
    49  		CurrentConfigBlockGetter: getLastConfigBlock,
    50  	}
    51  }
    52  
    53  // Config returns the channel's configuration
    54  func (s *DiscoverySupport) Config(channel string) (*discovery.ConfigResult, error) {
    55  	block := s.GetCurrConfigBlock(channel)
    56  	if block == nil {
    57  		return nil, errors.Errorf("could not get last config block for channel %s", channel)
    58  	}
    59  	if block.Data == nil || len(block.Data.Data) == 0 {
    60  		return nil, errors.Errorf("no transactions in block")
    61  	}
    62  	env := &common.Envelope{}
    63  	if err := proto.Unmarshal(block.Data.Data[0], env); err != nil {
    64  		return nil, errors.Wrap(err, "failed unmarshaling envelope")
    65  	}
    66  	pl := &common.Payload{}
    67  	if err := proto.Unmarshal(env.Payload, pl); err != nil {
    68  		return nil, errors.Wrap(err, "failed unmarshaling payload")
    69  	}
    70  	ce := &common.ConfigEnvelope{}
    71  	if err := proto.Unmarshal(pl.Data, ce); err != nil {
    72  		return nil, errors.Wrap(err, "failed unmarshaling config envelope")
    73  	}
    74  
    75  	if err := ValidateConfigEnvelope(ce); err != nil {
    76  		return nil, errors.Wrap(err, "config envelope is invalid")
    77  	}
    78  
    79  	res := &discovery.ConfigResult{
    80  		Msps:     make(map[string]*msp.FabricMSPConfig),
    81  		Orderers: make(map[string]*discovery.Endpoints),
    82  	}
    83  	ordererGrp := ce.Config.ChannelGroup.Groups[channelconfig.OrdererGroupKey].Groups
    84  	appGrp := ce.Config.ChannelGroup.Groups[channelconfig.ApplicationGroupKey].Groups
    85  
    86  	var globalEndpoints []string
    87  	globalOrderers := ce.Config.ChannelGroup.Values[channelconfig.OrdererAddressesKey]
    88  	if globalOrderers != nil {
    89  		ordererAddressesConfig := &common.OrdererAddresses{}
    90  		if err := proto.Unmarshal(globalOrderers.Value, ordererAddressesConfig); err != nil {
    91  			return nil, errors.Wrap(err, "failed unmarshaling orderer addresses")
    92  		}
    93  		globalEndpoints = ordererAddressesConfig.Addresses
    94  	}
    95  
    96  	ordererEndpoints, err := computeOrdererEndpoints(ordererGrp, globalEndpoints)
    97  	if err != nil {
    98  		return nil, errors.Wrap(err, "failed computing orderer addresses")
    99  	}
   100  	res.Orderers = ordererEndpoints
   101  
   102  	if err := appendMSPConfigs(ordererGrp, appGrp, res.Msps); err != nil {
   103  		return nil, errors.WithStack(err)
   104  	}
   105  	return res, nil
   106  
   107  }
   108  
   109  func computeOrdererEndpoints(ordererGrp map[string]*common.ConfigGroup, globalOrdererAddresses []string) (map[string]*discovery.Endpoints, error) {
   110  	endpointsByMSPID, err := perOrgEndpointsByMSPID(ordererGrp)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	var somePerOrgEndpoint bool
   116  	for _, perOrgEndpoints := range endpointsByMSPID {
   117  		if len(perOrgEndpoints) > 0 {
   118  			somePerOrgEndpoint = true
   119  			break
   120  		}
   121  	}
   122  
   123  	// Per org endpoints take precedence over global endpoints if applicable.
   124  	if somePerOrgEndpoint {
   125  		return computePerOrgEndpoints(endpointsByMSPID), nil
   126  	}
   127  
   128  	// Fallback to global endpoints if per org endpoints aren't configured.
   129  	return globalEndpoints(endpointsByMSPID, globalOrdererAddresses)
   130  }
   131  
   132  func computePerOrgEndpoints(endpointsByMSPID map[string][]string) map[string]*discovery.Endpoints {
   133  	res := make(map[string]*discovery.Endpoints)
   134  
   135  	for mspID, endpoints := range endpointsByMSPID {
   136  		res[mspID] = &discovery.Endpoints{}
   137  		for _, endpoint := range endpoints {
   138  			host, portStr, err := net.SplitHostPort(endpoint)
   139  			if err != nil {
   140  				logger.Warningf("Failed parsing endpoint %s for %s: %v", endpoint, mspID, err)
   141  				continue
   142  			}
   143  			port, err := strconv.ParseInt(portStr, 10, 32)
   144  			if err != nil {
   145  				logger.Warningf("%s for endpoint %s which belongs to %s is not a valid port number: %v", portStr, endpoint, mspID, err)
   146  				continue
   147  			}
   148  			res[mspID].Endpoint = append(res[mspID].Endpoint, &discovery.Endpoint{
   149  				Host: host,
   150  				Port: uint32(port),
   151  			})
   152  		}
   153  	}
   154  
   155  	return res
   156  }
   157  
   158  func perOrgEndpointsByMSPID(ordererGrp map[string]*common.ConfigGroup) (map[string][]string, error) {
   159  	res := make(map[string][]string)
   160  
   161  	for name, group := range ordererGrp {
   162  		mspConfig := &msp.MSPConfig{}
   163  		if err := proto.Unmarshal(group.Values[channelconfig.MSPKey].Value, mspConfig); err != nil {
   164  			return nil, errors.Wrap(err, "failed parsing MSPConfig")
   165  		}
   166  		// Skip non fabric MSPs, as they don't carry useful information for service discovery.
   167  		// An idemix MSP shouldn't appear inside an orderer group, but this isn't a fatal error
   168  		// for the discovery service and we can just ignore it.
   169  		if mspConfig.Type != int32(mspconstants.FABRIC) {
   170  			logger.Error("Orderer group", name, "is not a FABRIC MSP, but is of type", mspConfig.Type)
   171  			continue
   172  		}
   173  
   174  		fabricConfig := &msp.FabricMSPConfig{}
   175  		if err := proto.Unmarshal(mspConfig.Config, fabricConfig); err != nil {
   176  			return nil, errors.Wrap(err, "failed marshaling FabricMSPConfig")
   177  		}
   178  
   179  		// Initialize an empty MSP to address mapping.
   180  		res[fabricConfig.Name] = nil
   181  
   182  		// If the key has a corresponding value, it should unmarshal successfully.
   183  		if perOrgAddresses := group.Values[channelconfig.EndpointsKey]; perOrgAddresses != nil {
   184  			ordererEndpoints := &common.OrdererAddresses{}
   185  			if err := proto.Unmarshal(perOrgAddresses.Value, ordererEndpoints); err != nil {
   186  				return nil, errors.Wrap(err, "failed unmarshaling orderer addresses")
   187  			}
   188  			// Override the mapping because this orderer org config contains org-specific endpoints.
   189  			res[fabricConfig.Name] = ordererEndpoints.Addresses
   190  		}
   191  	}
   192  
   193  	return res, nil
   194  }
   195  
   196  func globalEndpoints(endpointsByMSPID map[string][]string, ordererAddresses []string) (map[string]*discovery.Endpoints, error) {
   197  	res := make(map[string]*discovery.Endpoints)
   198  
   199  	for mspID := range endpointsByMSPID {
   200  		res[mspID] = &discovery.Endpoints{}
   201  		for _, endpoint := range ordererAddresses {
   202  			host, portStr, err := net.SplitHostPort(endpoint)
   203  			if err != nil {
   204  				return nil, errors.Errorf("failed parsing orderer endpoint %s", endpoint)
   205  			}
   206  			port, err := strconv.ParseInt(portStr, 10, 32)
   207  			if err != nil {
   208  				return nil, errors.Errorf("%s is not a valid port number", portStr)
   209  			}
   210  			res[mspID].Endpoint = append(res[mspID].Endpoint, &discovery.Endpoint{
   211  				Host: host,
   212  				Port: uint32(port),
   213  			})
   214  		}
   215  	}
   216  	return res, nil
   217  }
   218  
   219  func appendMSPConfigs(ordererGrp, appGrp map[string]*common.ConfigGroup, output map[string]*msp.FabricMSPConfig) error {
   220  	for _, group := range []map[string]*common.ConfigGroup{ordererGrp, appGrp} {
   221  		for _, grp := range group {
   222  			mspConfig := &msp.MSPConfig{}
   223  			if err := proto.Unmarshal(grp.Values[channelconfig.MSPKey].Value, mspConfig); err != nil {
   224  				return errors.Wrap(err, "failed parsing MSPConfig")
   225  			}
   226  			// Skip non fabric MSPs, as they don't carry useful information for service discovery
   227  			if mspConfig.Type != int32(mspconstants.FABRIC) {
   228  				continue
   229  			}
   230  			fabricConfig := &msp.FabricMSPConfig{}
   231  			if err := proto.Unmarshal(mspConfig.Config, fabricConfig); err != nil {
   232  				return errors.Wrap(err, "failed marshaling FabricMSPConfig")
   233  			}
   234  			if _, exists := output[fabricConfig.Name]; exists {
   235  				continue
   236  			}
   237  			output[fabricConfig.Name] = fabricConfig
   238  		}
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  func ValidateConfigEnvelope(ce *common.ConfigEnvelope) error {
   245  	if ce.Config == nil {
   246  		return fmt.Errorf("field Config is nil")
   247  	}
   248  	if ce.Config.ChannelGroup == nil {
   249  		return fmt.Errorf("field Config.ChannelGroup is nil")
   250  	}
   251  	grps := ce.Config.ChannelGroup.Groups
   252  	if grps == nil {
   253  		return fmt.Errorf("field Config.ChannelGroup.Groups is nil")
   254  	}
   255  	for _, field := range []string{channelconfig.OrdererGroupKey, channelconfig.ApplicationGroupKey} {
   256  		grp, exists := grps[field]
   257  		if !exists {
   258  			return fmt.Errorf("key Config.ChannelGroup.Groups[%s] is missing", field)
   259  		}
   260  		if grp.Groups == nil {
   261  			return fmt.Errorf("key Config.ChannelGroup.Groups[%s].Groups is nil", field)
   262  		}
   263  	}
   264  	if ce.Config.ChannelGroup.Values == nil {
   265  		return fmt.Errorf("field Config.ChannelGroup.Values is nil")
   266  	}
   267  	return nil
   268  }