github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/coll_elg_notifier.go (about)

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