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