github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/cclifecycle/lifecycle.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cclifecycle
     8  
     9  import (
    10  	"sync"
    11  
    12  	"github.com/hechain20/hechain/common/chaincode"
    13  	"github.com/hechain20/hechain/common/flogging"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // Logger is the logging instance for this package.
    18  // It's exported because the tests override its backend
    19  var Logger = flogging.MustGetLogger("discovery.lifecycle")
    20  
    21  // MetadataManager manages information about lscc chaincodes.
    22  type MetadataManager struct {
    23  	sync.RWMutex
    24  	listeners              []MetadataChangeListener
    25  	installedCCs           []chaincode.InstalledChaincode
    26  	deployedCCsByChannel   map[string]*chaincode.MetadataMapping
    27  	queryCreatorsByChannel map[string]QueryCreator
    28  }
    29  
    30  //go:generate mockery -dir . -name MetadataChangeListener -case underscore  -output mocks/
    31  
    32  // MetadataChangeListener runs whenever there is a change to the metadata
    33  // of a chaincode in the context of a specific channel
    34  type MetadataChangeListener interface {
    35  	HandleMetadataUpdate(channel string, chaincodes chaincode.MetadataSet)
    36  }
    37  
    38  // HandleMetadataUpdateFunc is triggered upon a change in the chaincode lifecycle
    39  type HandleMetadataUpdateFunc func(channel string, chaincodes chaincode.MetadataSet)
    40  
    41  // HandleMetadataUpdate runs whenever there is a change to the metadata
    42  // of a chaincode in the context of a specific channel
    43  func (handleMetadataUpdate HandleMetadataUpdateFunc) HandleMetadataUpdate(channel string, chaincodes chaincode.MetadataSet) {
    44  	handleMetadataUpdate(channel, chaincodes)
    45  }
    46  
    47  //go:generate mockery -dir . -name Enumerator -case underscore  -output mocks/
    48  
    49  // Enumerator enumerates chaincodes
    50  type Enumerator interface {
    51  	// Enumerate returns the installed chaincodes
    52  	Enumerate() ([]chaincode.InstalledChaincode, error)
    53  }
    54  
    55  // EnumerateFunc enumerates installed chaincodes
    56  type EnumerateFunc func() ([]chaincode.InstalledChaincode, error)
    57  
    58  // Enumerate enumerates chaincodes
    59  func (enumerate EnumerateFunc) Enumerate() ([]chaincode.InstalledChaincode, error) {
    60  	return enumerate()
    61  }
    62  
    63  //go:generate mockery -dir . -name Query -case underscore  -output mocks/
    64  
    65  // Query queries the state
    66  type Query interface {
    67  	// GetState gets the value for given namespace and key. For a chaincode, the namespace corresponds to the chaincodeId
    68  	GetState(namespace string, key string) ([]byte, error)
    69  
    70  	// Done releases resources occupied by the QueryExecutor
    71  	Done()
    72  }
    73  
    74  //go:generate mockery -dir . -name QueryCreator -case underscore  -output mocks/
    75  
    76  // QueryCreator creates queries
    77  type QueryCreator interface {
    78  	// NewQuery creates a new Query, or error on failure
    79  	NewQuery() (Query, error)
    80  }
    81  
    82  // QueryCreatorFunc creates a new query
    83  type QueryCreatorFunc func() (Query, error)
    84  
    85  // NewQuery creates a new Query, or error on failure
    86  func (queryCreator QueryCreatorFunc) NewQuery() (Query, error) {
    87  	return queryCreator()
    88  }
    89  
    90  // NewMetadataManager creates a metadata manager for lscc chaincodes.
    91  func NewMetadataManager(installedChaincodes Enumerator) (*MetadataManager, error) {
    92  	installedCCs, err := installedChaincodes.Enumerate()
    93  	if err != nil {
    94  		return nil, errors.Wrap(err, "failed listing installed chaincodes")
    95  	}
    96  
    97  	return &MetadataManager{
    98  		installedCCs:           installedCCs,
    99  		deployedCCsByChannel:   map[string]*chaincode.MetadataMapping{},
   100  		queryCreatorsByChannel: map[string]QueryCreator{},
   101  	}, nil
   102  }
   103  
   104  // Metadata returns the metadata of the chaincode on the given channel,
   105  // or nil if not found or an error occurred at retrieving it
   106  func (m *MetadataManager) Metadata(channel string, cc string, collections ...string) *chaincode.Metadata {
   107  	queryCreator := m.queryCreatorsByChannel[channel]
   108  	if queryCreator == nil {
   109  		Logger.Warning("Requested Metadata for non-existent channel", channel)
   110  		return nil
   111  	}
   112  	// Search the metadata in our local cache, and if it exists - return it, but only if
   113  	// no collections were specified in the invocation.
   114  	if md, found := m.deployedCCsByChannel[channel].Lookup(cc); found && len(collections) == 0 {
   115  		Logger.Debug("Returning metadata for channel", channel, ", chaincode", cc, ":", md)
   116  		return &md
   117  	}
   118  	query, err := queryCreator.NewQuery()
   119  	if err != nil {
   120  		Logger.Error("Failed obtaining new query for channel", channel, ":", err)
   121  		return nil
   122  	}
   123  	md, err := DeployedChaincodes(query, AcceptAll, len(collections) > 0, cc)
   124  	if err != nil {
   125  		Logger.Error("Failed querying LSCC for channel", channel, ":", err)
   126  		return nil
   127  	}
   128  	if len(md) == 0 {
   129  		Logger.Warn("Chaincode", cc, "isn't defined in channel", channel)
   130  		return nil
   131  	}
   132  
   133  	return &md[0]
   134  }
   135  
   136  func (m *MetadataManager) initMetadataForChannel(channel string, queryCreator QueryCreator) error {
   137  	if m.isChannelMetadataInitialized(channel) {
   138  		return nil
   139  	}
   140  	// Create a new metadata mapping for the channel
   141  	query, err := queryCreator.NewQuery()
   142  	if err != nil {
   143  		return errors.WithStack(err)
   144  	}
   145  	ccs, err := queryChaincodeDefinitions(query, m.installedCCs, DeployedChaincodes)
   146  	if err != nil {
   147  		return errors.WithStack(err)
   148  	}
   149  	m.createMetadataForChannel(channel, queryCreator)
   150  	m.updateState(channel, ccs)
   151  	return nil
   152  }
   153  
   154  func (m *MetadataManager) createMetadataForChannel(channel string, newQuery QueryCreator) {
   155  	m.Lock()
   156  	defer m.Unlock()
   157  	m.deployedCCsByChannel[channel] = chaincode.NewMetadataMapping()
   158  	m.queryCreatorsByChannel[channel] = newQuery
   159  }
   160  
   161  func (m *MetadataManager) isChannelMetadataInitialized(channel string) bool {
   162  	m.RLock()
   163  	defer m.RUnlock()
   164  	_, exists := m.deployedCCsByChannel[channel]
   165  	return exists
   166  }
   167  
   168  func (m *MetadataManager) updateState(channel string, ccUpdate chaincode.MetadataSet) {
   169  	m.RLock()
   170  	defer m.RUnlock()
   171  	for _, cc := range ccUpdate {
   172  		m.deployedCCsByChannel[channel].Update(cc)
   173  	}
   174  }
   175  
   176  func (m *MetadataManager) fireChangeListeners(channel string) {
   177  	m.RLock()
   178  	md := m.deployedCCsByChannel[channel]
   179  	m.RUnlock()
   180  	for _, listener := range m.listeners {
   181  		aggregatedMD := md.Aggregate()
   182  		listener.HandleMetadataUpdate(channel, aggregatedMD)
   183  	}
   184  	Logger.Debug("Listeners for channel", channel, "invoked")
   185  }
   186  
   187  // NewChannelSubscription subscribes to a channel
   188  func (m *MetadataManager) NewChannelSubscription(channel string, queryCreator QueryCreator) (*Subscription, error) {
   189  	sub := &Subscription{
   190  		metadataManager: m,
   191  		channel:         channel,
   192  		queryCreator:    queryCreator,
   193  	}
   194  	// Initialize metadata for the channel.
   195  	// This loads metadata about all installed chaincodes
   196  	if err := m.initMetadataForChannel(channel, queryCreator); err != nil {
   197  		return nil, errors.WithStack(err)
   198  	}
   199  	m.fireChangeListeners(channel)
   200  	return sub, nil
   201  }
   202  
   203  // AddListener registers the given listener to be triggered upon a lifecycle change
   204  func (m *MetadataManager) AddListener(listener MetadataChangeListener) {
   205  	m.Lock()
   206  	defer m.Unlock()
   207  	m.listeners = append(m.listeners, listener)
   208  }