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