github.com/true-sqn/fabric@v2.1.1+incompatible/core/common/privdata/store.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package privdata 8 9 import ( 10 "fmt" 11 12 "github.com/golang/protobuf/proto" 13 "github.com/hyperledger/fabric-protos-go/peer" 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 "github.com/hyperledger/fabric/core/ledger" 16 "github.com/hyperledger/fabric/msp" 17 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 18 "github.com/hyperledger/fabric/protoutil" 19 "github.com/pkg/errors" 20 ) 21 22 // State retrieves data from the state. 23 type State interface { 24 // GetState retrieves the value for the given key in the given namespace 25 GetState(namespace string, key string) ([]byte, error) 26 } 27 28 type NoSuchCollectionError CollectionCriteria 29 30 func (f NoSuchCollectionError) Error() string { 31 return fmt.Sprintf("collection %s/%s/%s could not be found", f.Channel, f.Namespace, f.Collection) 32 } 33 34 // A QueryExecutorFactory is responsible for creating ledger.QueryExectuor 35 // instances. 36 type QueryExecutorFactory interface { 37 NewQueryExecutor() (ledger.QueryExecutor, error) 38 } 39 40 // ChaincodeInfoProvider provides information about deployed chaincode. 41 // LSCC module is expected to provide an implementation for this dependencys 42 type ChaincodeInfoProvider interface { 43 // ChaincodeInfo returns the info about a deployed chaincode. 44 ChaincodeInfo(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) 45 // CollectionInfo returns the proto msg that defines the named collection. 46 // This function can be used for both explicit and implicit collections. 47 CollectionInfo(channelName, chaincodeName, collectionName string, qe ledger.SimpleQueryExecutor) (*peer.StaticCollectionConfig, error) 48 // AllCollectionsConfigPkg returns a combined collection config pkg that contains both explicit and implicit collections 49 AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*peer.CollectionConfigPackage, error) 50 } 51 52 // IdentityDeserializerFactory creates msp.IdentityDeserializer for 53 // a chain. 54 type IdentityDeserializerFactory interface { 55 GetIdentityDeserializer(chainID string) msp.IdentityDeserializer 56 } 57 58 // IdentityDeserializerFactoryFunc is a function adapater for 59 // IdentityDeserializerFactory. 60 type IdentityDeserializerFactoryFunc func(chainID string) msp.IdentityDeserializer 61 62 func (i IdentityDeserializerFactoryFunc) GetIdentityDeserializer(chainID string) msp.IdentityDeserializer { 63 return i(chainID) 64 } 65 66 // CollectionCriteria defines an element of a private data that corresponds 67 // to a certain transaction and collection 68 type CollectionCriteria struct { 69 Channel string 70 Collection string 71 Namespace string 72 } 73 74 type SimpleCollectionStore struct { 75 qeFactory QueryExecutorFactory 76 ccInfoProvider ChaincodeInfoProvider 77 idDeserializerFactory IdentityDeserializerFactory 78 } 79 80 func NewSimpleCollectionStore(qeFactory QueryExecutorFactory, ccInfoProvider ChaincodeInfoProvider) *SimpleCollectionStore { 81 return &SimpleCollectionStore{ 82 qeFactory: qeFactory, 83 ccInfoProvider: ccInfoProvider, 84 idDeserializerFactory: IdentityDeserializerFactoryFunc(func(chainID string) msp.IdentityDeserializer { 85 return mspmgmt.GetManagerForChain(chainID) 86 }), 87 } 88 } 89 90 func (c *SimpleCollectionStore) retrieveCollectionConfigPackage(cc CollectionCriteria, qe ledger.QueryExecutor) (*peer.CollectionConfigPackage, error) { 91 var err error 92 if qe == nil { 93 qe, err = c.qeFactory.NewQueryExecutor() 94 if err != nil { 95 return nil, errors.WithMessagef(err, "could not retrieve query executor for collection criteria %#v", cc) 96 } 97 defer qe.Done() 98 } 99 return c.ccInfoProvider.AllCollectionsConfigPkg(cc.Channel, cc.Namespace, qe) 100 } 101 102 // RetrieveCollectionConfigPackageFromState retrieves the collection config package from the given key from the given state 103 func RetrieveCollectionConfigPackageFromState(cc CollectionCriteria, state State) (*peer.CollectionConfigPackage, error) { 104 cb, err := state.GetState("lscc", BuildCollectionKVSKey(cc.Namespace)) 105 if err != nil { 106 return nil, errors.WithMessagef(err, "error while retrieving collection for collection criteria %#v", cc) 107 } 108 if cb == nil { 109 return nil, NoSuchCollectionError(cc) 110 } 111 conf, err := ParseCollectionConfig(cb) 112 if err != nil { 113 return nil, errors.Wrapf(err, "invalid configuration for collection criteria %#v", cc) 114 } 115 return conf, nil 116 } 117 118 // ParseCollectionConfig parses the collection configuration from the given serialized representation. 119 func ParseCollectionConfig(colBytes []byte) (*peer.CollectionConfigPackage, error) { 120 collections := &peer.CollectionConfigPackage{} 121 err := proto.Unmarshal(colBytes, collections) 122 if err != nil { 123 return nil, errors.WithStack(err) 124 } 125 126 return collections, nil 127 } 128 129 // RetrieveCollectionConfig retrieves a collection's config 130 func (c *SimpleCollectionStore) RetrieveCollectionConfig(cc CollectionCriteria) (*peer.StaticCollectionConfig, error) { 131 return c.retrieveCollectionConfig(cc, nil) 132 } 133 134 func (c *SimpleCollectionStore) retrieveCollectionConfig(cc CollectionCriteria, qe ledger.QueryExecutor) (*peer.StaticCollectionConfig, error) { 135 var err error 136 if qe == nil { 137 qe, err = c.qeFactory.NewQueryExecutor() 138 if err != nil { 139 return nil, errors.WithMessagef(err, "could not retrieve query executor for collection criteria %#v", cc) 140 } 141 defer qe.Done() 142 } 143 collConfig, err := c.ccInfoProvider.CollectionInfo(cc.Channel, cc.Namespace, cc.Collection, qe) 144 if err != nil { 145 return nil, err 146 } 147 if collConfig == nil { 148 return nil, NoSuchCollectionError(cc) 149 } 150 return collConfig, nil 151 } 152 153 func (c *SimpleCollectionStore) retrieveSimpleCollection(cc CollectionCriteria, qe ledger.QueryExecutor) (*SimpleCollection, error) { 154 staticCollectionConfig, err := c.retrieveCollectionConfig(cc, qe) 155 if err != nil { 156 return nil, err 157 } 158 sc := &SimpleCollection{} 159 err = sc.Setup(staticCollectionConfig, c.idDeserializerFactory.GetIdentityDeserializer(cc.Channel)) 160 if err != nil { 161 return nil, errors.WithMessagef(err, "error setting up collection for collection criteria %#v", cc) 162 } 163 return sc, nil 164 } 165 166 func (c *SimpleCollectionStore) AccessFilter(channelName string, collectionPolicyConfig *peer.CollectionPolicyConfig) (Filter, error) { 167 sc := &SimpleCollection{} 168 err := sc.setupAccessPolicy(collectionPolicyConfig, c.idDeserializerFactory.GetIdentityDeserializer(channelName)) 169 if err != nil { 170 return nil, err 171 } 172 return sc.AccessFilter(), nil 173 } 174 175 func (c *SimpleCollectionStore) RetrieveCollection(cc CollectionCriteria) (Collection, error) { 176 return c.retrieveSimpleCollection(cc, nil) 177 } 178 179 func (c *SimpleCollectionStore) RetrieveCollectionAccessPolicy(cc CollectionCriteria) (CollectionAccessPolicy, error) { 180 return c.retrieveSimpleCollection(cc, nil) 181 } 182 183 func (c *SimpleCollectionStore) RetrieveCollectionConfigPackage(cc CollectionCriteria) (*peer.CollectionConfigPackage, error) { 184 return c.retrieveCollectionConfigPackage(cc, nil) 185 } 186 187 // RetrieveCollectionPersistenceConfigs retrieves the collection's persistence related configurations 188 func (c *SimpleCollectionStore) RetrieveCollectionPersistenceConfigs(cc CollectionCriteria) (CollectionPersistenceConfigs, error) { 189 staticCollectionConfig, err := c.retrieveCollectionConfig(cc, nil) 190 if err != nil { 191 return nil, err 192 } 193 return &SimpleCollectionPersistenceConfigs{staticCollectionConfig.BlockToLive}, nil 194 } 195 196 // RetrieveReadWritePermission retrieves the read-write persmission of the creator of the 197 // signedProposal for a given collection using collection access policy and flags such as 198 // memberOnlyRead & memberOnlyWrite 199 func (c *SimpleCollectionStore) RetrieveReadWritePermission( 200 cc CollectionCriteria, 201 signedProposal *pb.SignedProposal, 202 qe ledger.QueryExecutor, 203 ) (bool, bool, error) { 204 collection, err := c.retrieveSimpleCollection(cc, qe) 205 if err != nil { 206 return false, false, err 207 } 208 209 if canAnyoneReadAndWrite(collection) { 210 return true, true, nil 211 } 212 213 // all members have read-write persmission 214 if isAMember, err := isCreatorOfProposalAMember(signedProposal, collection); err != nil { 215 return false, false, err 216 } else if isAMember { 217 return true, true, nil 218 } 219 220 return !collection.IsMemberOnlyRead(), !collection.IsMemberOnlyWrite(), nil 221 } 222 223 func canAnyoneReadAndWrite(collection *SimpleCollection) bool { 224 if !collection.IsMemberOnlyRead() && !collection.IsMemberOnlyWrite() { 225 return true 226 } 227 return false 228 } 229 230 func isCreatorOfProposalAMember(signedProposal *pb.SignedProposal, collection *SimpleCollection) (bool, error) { 231 signedData, err := getSignedData(signedProposal) 232 if err != nil { 233 return false, err 234 } 235 236 accessFilter := collection.AccessFilter() 237 return accessFilter(signedData), nil 238 } 239 240 func getSignedData(signedProposal *pb.SignedProposal) (protoutil.SignedData, error) { 241 proposal, err := protoutil.UnmarshalProposal(signedProposal.ProposalBytes) 242 if err != nil { 243 return protoutil.SignedData{}, err 244 } 245 246 hdr, err := protoutil.UnmarshalHeader(proposal.Header) 247 if err != nil { 248 return protoutil.SignedData{}, err 249 } 250 251 shdr, err := protoutil.UnmarshalSignatureHeader(hdr.SignatureHeader) 252 if err != nil { 253 return protoutil.SignedData{}, err 254 } 255 256 return protoutil.SignedData{ 257 Data: signedProposal.ProposalBytes, 258 Identity: shdr.Creator, 259 Signature: signedProposal.Signature, 260 }, nil 261 }