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  }