github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/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 // 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 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) { 95 listener := n.listeners[ledgerID] 96 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 103 collectionNames := []string{} 104 exisingConfs := retrieveCollConfs(existingPkg) 105 postCommitConfs := retrieveCollConfs(postCommitPkg) 106 existingConfMap := map[string]*peer.StaticCollectionConfig{} 107 for _, existingConf := range exisingConfs { 108 existingConfMap[existingConf.Name] = existingConf 109 } 110 111 for _, postCommitConf := range postCommitConfs { 112 collName := postCommitConf.Name 113 existingConf, ok := existingConfMap[collName] 114 if !ok { // brand new collection 115 continue 116 } 117 membershipEnabled, err := n.elgEnabled(ledgerID, existingConf.MemberOrgsPolicy, postCommitConf.MemberOrgsPolicy) 118 if err != nil { 119 return nil, err 120 } 121 if !membershipEnabled { 122 continue 123 } 124 // not an existing member and added now 125 collectionNames = append(collectionNames, collName) 126 } 127 return collectionNames, nil 128 } 129 130 // elgEnabled returns true if the peer is not eligible for a collection as per 'existingPolicy' and is eligible as per 'postCommitPolicy' 131 func (n *collElgNotifier) elgEnabled(ledgerID string, existingPolicy, postCommitPolicy *peer.CollectionPolicyConfig) (bool, error) { 132 existingMember, err := n.membershipInfoProvider.AmMemberOf(ledgerID, existingPolicy) 133 if err != nil || existingMember { 134 return false, err 135 } 136 return n.membershipInfoProvider.AmMemberOf(ledgerID, postCommitPolicy) 137 } 138 139 func extractPublicUpdates(stateUpdates ledger.StateUpdates) map[string][]*kvrwset.KVWrite { 140 m := map[string][]*kvrwset.KVWrite{} 141 for ns, updates := range stateUpdates { 142 m[ns] = updates.PublicUpdates 143 } 144 return m 145 } 146 147 // StateCommitDone implements function in interface ledger.StateListener 148 func (n *collElgNotifier) StateCommitDone(ledgerID string) { 149 // Noop 150 } 151 152 type collElgListener interface { 153 ProcessCollsEligibilityEnabled(commitingBlk uint64, nsCollMap map[string][]string) error 154 } 155 156 func retrieveCollConfs(collConfPkg *peer.CollectionConfigPackage) []*peer.StaticCollectionConfig { 157 if collConfPkg == nil { 158 return nil 159 } 160 var staticCollConfs []*peer.StaticCollectionConfig 161 protoConfArray := collConfPkg.Config 162 for _, protoConf := range protoConfArray { 163 staticCollConfs = append(staticCollConfs, protoConf.GetStaticCollectionConfig()) 164 } 165 return staticCollConfs 166 }