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 }