github.com/lzy4123/fabric@v2.1.1+incompatible/internal/pkg/peer/orderers/connection.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package orderers 8 9 import ( 10 "bytes" 11 "crypto/sha256" 12 "crypto/x509" 13 "math/rand" 14 "sync" 15 16 "github.com/hyperledger/fabric/common/flogging" 17 "github.com/hyperledger/fabric/internal/pkg/comm" 18 19 "github.com/pkg/errors" 20 ) 21 22 type ConnectionSource struct { 23 mutex sync.RWMutex 24 allEndpoints []*Endpoint 25 orgToEndpointsHash map[string][]byte 26 logger *flogging.FabricLogger 27 overrides map[string]*Endpoint 28 } 29 30 type Endpoint struct { 31 Address string 32 CertPool *x509.CertPool 33 Refreshed chan struct{} 34 } 35 36 type OrdererOrg struct { 37 Addresses []string 38 RootCerts [][]byte 39 } 40 41 func NewConnectionSource(logger *flogging.FabricLogger, overrides map[string]*Endpoint) *ConnectionSource { 42 return &ConnectionSource{ 43 orgToEndpointsHash: map[string][]byte{}, 44 logger: logger, 45 overrides: overrides, 46 } 47 } 48 49 func (cs *ConnectionSource) RandomEndpoint() (*Endpoint, error) { 50 cs.mutex.RLock() 51 defer cs.mutex.RUnlock() 52 if len(cs.allEndpoints) == 0 { 53 return nil, errors.Errorf("no endpoints currently defined") 54 } 55 return cs.allEndpoints[rand.Intn(len(cs.allEndpoints))], nil 56 } 57 58 func (cs *ConnectionSource) Update(globalAddrs []string, orgs map[string]OrdererOrg) { 59 cs.mutex.Lock() 60 defer cs.mutex.Unlock() 61 cs.logger.Debug("Processing updates for orderer endpoints") 62 63 newOrgToEndpointsHash := map[string][]byte{} 64 65 anyChange := false 66 hasOrgEndpoints := false 67 for orgName, org := range orgs { 68 hasher := sha256.New() 69 for _, cert := range org.RootCerts { 70 hasher.Write(cert) 71 } 72 for _, address := range org.Addresses { 73 hasOrgEndpoints = true 74 hasher.Write([]byte(address)) 75 } 76 hash := hasher.Sum(nil) 77 78 newOrgToEndpointsHash[orgName] = hash 79 80 lastHash, ok := cs.orgToEndpointsHash[orgName] 81 if ok && bytes.Equal(hash, lastHash) { 82 continue 83 } 84 85 cs.logger.Debugf("Found orderer org '%s' has updates", orgName) 86 anyChange = true 87 } 88 89 for orgName := range cs.orgToEndpointsHash { 90 if _, ok := orgs[orgName]; !ok { 91 // An org that used to exist has been removed 92 cs.logger.Debugf("Found orderer org '%s' has been removed", orgName) 93 anyChange = true 94 } 95 } 96 97 cs.orgToEndpointsHash = newOrgToEndpointsHash 98 99 if hasOrgEndpoints && len(globalAddrs) > 0 { 100 cs.logger.Warning("Config defines both orderer org specific endpoints and global endpoints, global endpoints will be ignored") 101 } 102 103 if !hasOrgEndpoints && len(globalAddrs) != len(cs.allEndpoints) { 104 cs.logger.Debugf("There are no org endpoints, but the global addresses have changed") 105 anyChange = true 106 } 107 108 if !hasOrgEndpoints && !anyChange && len(globalAddrs) == len(cs.allEndpoints) { 109 // There are no org endpoints, there were no org endpoints, and the number 110 // of the update's global endpoints is the same as the number of existing endpoints. 111 // So, we check if any of the endpoints addresses differ. 112 113 newAddresses := map[string]struct{}{} 114 for _, address := range globalAddrs { 115 newAddresses[address] = struct{}{} 116 } 117 118 for _, endpoint := range cs.allEndpoints { 119 delete(newAddresses, endpoint.Address) 120 } 121 122 // Set anyChange true if some new address was not 123 // in the set of old endpoints. 124 anyChange = len(newAddresses) != 0 125 if anyChange { 126 cs.logger.Debugf("There are no org endpoints, but some of the global addresses have changed") 127 } 128 } 129 130 if !anyChange { 131 cs.logger.Debugf("No orderer endpoint addresses or TLS certs were changed") 132 // No TLS certs changed, no org specified endpoints changed, 133 // and if we are using global endpoints, they are the same 134 // as our last set. No need to update anything. 135 return 136 } 137 138 for _, endpoint := range cs.allEndpoints { 139 // Alert any existing consumers that have a reference to the old endpoints 140 // that their reference is now stale and they should get a new one. 141 // This is done even for endpoints which have the same TLS certs and address 142 // but this is desirable to help load balance. For instance if only 143 // one orderer were defined, and the config is updated to include 4 more, we 144 // want the peers to disconnect from that original orderer and reconnect 145 // evenly across the now five. 146 close(endpoint.Refreshed) 147 } 148 149 cs.allEndpoints = nil 150 151 globalCertPool := x509.NewCertPool() 152 153 for orgName, org := range orgs { 154 certPool := x509.NewCertPool() 155 for _, rootCert := range org.RootCerts { 156 if hasOrgEndpoints { 157 if err := comm.AddPemToCertPool(rootCert, certPool); err != nil { 158 cs.logger.Warningf("Could not add orderer cert for org '%s' to cert pool: %s", orgName, err) 159 } 160 } else { 161 if err := comm.AddPemToCertPool(rootCert, globalCertPool); err != nil { 162 cs.logger.Warningf("Could not add orderer cert for org '%s' to global cert pool: %s", orgName, err) 163 164 } 165 } 166 } 167 168 // Note, if !hasOrgEndpoints, this for loop is a no-op, so 169 // certPool is never referenced. 170 for _, address := range org.Addresses { 171 overrideEndpoint, ok := cs.overrides[address] 172 if ok { 173 cs.allEndpoints = append(cs.allEndpoints, &Endpoint{ 174 Address: overrideEndpoint.Address, 175 CertPool: overrideEndpoint.CertPool, 176 Refreshed: make(chan struct{}), 177 }) 178 continue 179 } 180 181 cs.allEndpoints = append(cs.allEndpoints, &Endpoint{ 182 Address: address, 183 CertPool: certPool, 184 Refreshed: make(chan struct{}), 185 }) 186 } 187 } 188 189 if len(cs.allEndpoints) != 0 { 190 cs.logger.Debugf("Returning an orderer connection pool source with org specific endpoints only") 191 // There are some org specific endpoints, so we do not 192 // add any of the global endpoints to our pool. 193 return 194 } 195 196 for _, address := range globalAddrs { 197 overrideEndpoint, ok := cs.overrides[address] 198 if ok { 199 cs.allEndpoints = append(cs.allEndpoints, &Endpoint{ 200 Address: overrideEndpoint.Address, 201 CertPool: overrideEndpoint.CertPool, 202 Refreshed: make(chan struct{}), 203 }) 204 continue 205 } 206 207 cs.allEndpoints = append(cs.allEndpoints, &Endpoint{ 208 Address: address, 209 CertPool: globalCertPool, 210 Refreshed: make(chan struct{}), 211 }) 212 } 213 214 cs.logger.Debugf("Returning an orderer connection pool source with global endpoints only") 215 }