github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/coll_elg_notifier.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    11  	"github.com/hyperledger/fabric-protos-go/peer"
    12  	"github.com/hyperledger/fabric/core/ledger"
    13  )
    14  
    15  // collElgNotifier listens for the chaincode events and determines whether the peer has become eligible for one or more existing
    16  // private data collections and notifies the registered listener
    17  type collElgNotifier struct {
    18  	deployedChaincodeInfoProvider ledger.DeployedChaincodeInfoProvider
    19  	membershipInfoProvider        ledger.MembershipInfoProvider
    20  	listeners                     map[string]collElgListener
    21  }
    22  
    23  func (n *collElgNotifier) Initialize(ledgerID string, qe ledger.SimpleQueryExecutor) error {
    24  	// Noop
    25  	return nil
    26  }
    27  
    28  // InterestedInNamespaces implements function in interface ledger.StateListener
    29  func (n *collElgNotifier) InterestedInNamespaces() []string {
    30  	return n.deployedChaincodeInfoProvider.Namespaces()
    31  }
    32  
    33  // HandleStateUpdates implements function in interface ledger.StateListener
    34  // This function gets invoked when one or more chaincodes are deployed or upgraded by a block.
    35  // This function, for each upgraded chaincode, performs the following
    36  // 1) Retrieves the existing collection configurations and new collection configurations
    37  // 2) Computes the collections for which the peer is not eligible as per the existing collection configuration
    38  //    but is eligible as per the new collection configuration
    39  // Finally, it causes an invocation to function 'ProcessCollsEligibilityEnabled' on ledger store with a map {ns:colls}
    40  // that contains the details of <ns, coll> combination for which the eligibility of the peer is switched on.
    41  func (n *collElgNotifier) HandleStateUpdates(trigger *ledger.StateUpdateTrigger) error {
    42  	nsCollMap := map[string][]string{}
    43  	qe := trigger.CommittedStateQueryExecutor
    44  	postCommitQE := trigger.PostCommitQueryExecutor
    45  
    46  	stateUpdates := extractPublicUpdates(trigger.StateUpdates)
    47  	ccLifecycleInfo, err := n.deployedChaincodeInfoProvider.UpdatedChaincodes(stateUpdates)
    48  	if err != nil {
    49  		return err
    50  	}
    51  	var existingCCInfo, postCommitCCInfo *ledger.DeployedChaincodeInfo
    52  	for _, ccInfo := range ccLifecycleInfo {
    53  		ledgerid := trigger.LedgerID
    54  		ccName := ccInfo.Name
    55  		if existingCCInfo, err = n.deployedChaincodeInfoProvider.ChaincodeInfo(ledgerid, ccName, qe); err != nil {
    56  			return err
    57  		}
    58  		if existingCCInfo == nil { // not an upgrade transaction
    59  			continue
    60  		}
    61  		if postCommitCCInfo, err = n.deployedChaincodeInfoProvider.ChaincodeInfo(ledgerid, ccName, postCommitQE); err != nil {
    62  			return err
    63  		}
    64  		elgEnabledCollNames, err := n.elgEnabledCollNames(
    65  			ledgerid,
    66  			existingCCInfo.ExplicitCollectionConfigPkg,
    67  			postCommitCCInfo.ExplicitCollectionConfigPkg,
    68  		)
    69  		if err != nil {
    70  			return err
    71  		}
    72  		logger.Debugf("[%s] collections of chaincode [%s] for which peer was not eligible before and now the eligiblity is enabled - [%s]",
    73  			ledgerid, ccName, elgEnabledCollNames,
    74  		)
    75  		if len(elgEnabledCollNames) > 0 {
    76  			nsCollMap[ccName] = elgEnabledCollNames
    77  		}
    78  	}
    79  	if len(nsCollMap) > 0 {
    80  		n.invokeLedgerSpecificNotifier(trigger.LedgerID, trigger.CommittingBlockNum, nsCollMap)
    81  	}
    82  	return nil
    83  }
    84  
    85  func (n *collElgNotifier) registerListener(ledgerID string, listener collElgListener) {
    86  	n.listeners[ledgerID] = listener
    87  }
    88  
    89  func (n *collElgNotifier) invokeLedgerSpecificNotifier(ledgerID string, commtingBlk uint64, nsCollMap map[string][]string) {
    90  	listener := n.listeners[ledgerID]
    91  	listener.ProcessCollsEligibilityEnabled(commtingBlk, nsCollMap)
    92  }
    93  
    94  // elgEnabledCollNames returns the names of the collections for which the peer is not eligible as per 'existingPkg' and is eligible as per 'postCommitPkg'
    95  func (n *collElgNotifier) elgEnabledCollNames(ledgerID string,
    96  	existingPkg, postCommitPkg *peer.CollectionConfigPackage) ([]string, error) {
    97  
    98  	collectionNames := []string{}
    99  	exisingConfs := retrieveCollConfs(existingPkg)
   100  	postCommitConfs := retrieveCollConfs(postCommitPkg)
   101  	existingConfMap := map[string]*peer.StaticCollectionConfig{}
   102  	for _, existingConf := range exisingConfs {
   103  		existingConfMap[existingConf.Name] = existingConf
   104  	}
   105  
   106  	for _, postCommitConf := range postCommitConfs {
   107  		collName := postCommitConf.Name
   108  		existingConf, ok := existingConfMap[collName]
   109  		if !ok { // brand new collection
   110  			continue
   111  		}
   112  		membershipEnabled, err := n.elgEnabled(ledgerID, existingConf.MemberOrgsPolicy, postCommitConf.MemberOrgsPolicy)
   113  		if err != nil {
   114  			return nil, err
   115  		}
   116  		if !membershipEnabled {
   117  			continue
   118  		}
   119  		// not an existing member and added now
   120  		collectionNames = append(collectionNames, collName)
   121  	}
   122  	return collectionNames, nil
   123  }
   124  
   125  // elgEnabled returns true if the peer is not eligible for a collection as per 'existingPolicy' and is eligible as per 'postCommitPolicy'
   126  func (n *collElgNotifier) elgEnabled(ledgerID string, existingPolicy, postCommitPolicy *peer.CollectionPolicyConfig) (bool, error) {
   127  	existingMember, err := n.membershipInfoProvider.AmMemberOf(ledgerID, existingPolicy)
   128  	if err != nil || existingMember {
   129  		return false, err
   130  	}
   131  	return n.membershipInfoProvider.AmMemberOf(ledgerID, postCommitPolicy)
   132  }
   133  
   134  func extractPublicUpdates(stateUpdates ledger.StateUpdates) map[string][]*kvrwset.KVWrite {
   135  	m := map[string][]*kvrwset.KVWrite{}
   136  	for ns, updates := range stateUpdates {
   137  		m[ns] = updates.PublicUpdates
   138  	}
   139  	return m
   140  }
   141  
   142  // StateCommitDone implements function in interface ledger.StateListener
   143  func (n *collElgNotifier) StateCommitDone(ledgerID string) {
   144  	// Noop
   145  }
   146  
   147  type collElgListener interface {
   148  	ProcessCollsEligibilityEnabled(commitingBlk uint64, nsCollMap map[string][]string) error
   149  }
   150  
   151  func retrieveCollConfs(collConfPkg *peer.CollectionConfigPackage) []*peer.StaticCollectionConfig {
   152  	if collConfPkg == nil {
   153  		return nil
   154  	}
   155  	var staticCollConfs []*peer.StaticCollectionConfig
   156  	protoConfArray := collConfPkg.Config
   157  	for _, protoConf := range protoConfArray {
   158  		staticCollConfs = append(staticCollConfs, protoConf.GetStaticCollectionConfig())
   159  	}
   160  	return staticCollConfs
   161  }