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 }