github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/discovery/support/config/support.go (about)

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