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