github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/common/privdata/store.go (about) 1 /* 2 Copyright hechain. 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/hechain20/hechain/core/ledger" 14 "github.com/hechain20/hechain/msp" 15 "github.com/hechain20/hechain/protoutil" 16 "github.com/hyperledger/fabric-protos-go/peer" 17 "github.com/pkg/errors" 18 ) 19 20 // State retrieves data from the state. 21 type State interface { 22 // GetState retrieves the value for the given key in the given namespace 23 GetState(namespace string, key string) ([]byte, error) 24 } 25 26 type NoSuchCollectionError CollectionCriteria 27 28 func (f NoSuchCollectionError) Error() string { 29 return fmt.Sprintf("collection %s/%s/%s could not be found", f.Channel, f.Namespace, f.Collection) 30 } 31 32 // A QueryExecutorFactory is responsible for creating ledger.QueryExectuor 33 // instances. 34 type QueryExecutorFactory interface { 35 NewQueryExecutor() (ledger.QueryExecutor, error) 36 } 37 38 // ChaincodeInfoProvider provides information about deployed chaincode. 39 // LSCC module is expected to provide an implementation for this dependencys 40 type ChaincodeInfoProvider interface { 41 // ChaincodeInfo returns the info about a deployed chaincode. 42 ChaincodeInfo(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) 43 // CollectionInfo returns the proto msg that defines the named collection. 44 // This function can be used for both explicit and implicit collections. 45 CollectionInfo(channelName, chaincodeName, collectionName string, qe ledger.SimpleQueryExecutor) (*peer.StaticCollectionConfig, error) 46 // AllCollectionsConfigPkg returns a combined collection config pkg that contains both explicit and implicit collections 47 AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*peer.CollectionConfigPackage, error) 48 } 49 50 // IdentityDeserializerFactory creates msp.IdentityDeserializer for 51 // a chain. 52 type IdentityDeserializerFactory interface { 53 GetIdentityDeserializer(chainID string) msp.IdentityDeserializer 54 } 55 56 // IdentityDeserializerFactoryFunc is a function adapater for 57 // IdentityDeserializerFactory. 58 type IdentityDeserializerFactoryFunc func(chainID string) msp.IdentityDeserializer 59 60 func (i IdentityDeserializerFactoryFunc) GetIdentityDeserializer(chainID string) msp.IdentityDeserializer { 61 return i(chainID) 62 } 63 64 // CollectionCriteria defines an element of a private data that corresponds 65 // to a certain transaction and collection 66 type CollectionCriteria struct { 67 Channel string 68 Collection string 69 Namespace string 70 } 71 72 type SimpleCollectionStore struct { 73 qeFactory QueryExecutorFactory 74 ccInfoProvider ChaincodeInfoProvider 75 idDeserializerFactory IdentityDeserializerFactory 76 } 77 78 func NewSimpleCollectionStore( 79 qeFactory QueryExecutorFactory, 80 ccInfoProvider ChaincodeInfoProvider, 81 idDeserializerFactory IdentityDeserializerFactory, 82 ) *SimpleCollectionStore { 83 return &SimpleCollectionStore{ 84 qeFactory: qeFactory, 85 ccInfoProvider: ccInfoProvider, 86 idDeserializerFactory: idDeserializerFactory, 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 permission 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 *peer.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 permission 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 *peer.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 *peer.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 }