github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/committer/txvalidator/v14/plugin_validator.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package txvalidator 8 9 import ( 10 "fmt" 11 "sync" 12 13 "github.com/hyperledger/fabric-protos-go/common" 14 "github.com/hyperledger/fabric/common/cauthdsl" 15 ledger2 "github.com/hyperledger/fabric/common/ledger" 16 vp "github.com/hyperledger/fabric/core/committer/txvalidator/plugin" 17 validation "github.com/hyperledger/fabric/core/handlers/validation/api" 18 vc "github.com/hyperledger/fabric/core/handlers/validation/api/capabilities" 19 vi "github.com/hyperledger/fabric/core/handlers/validation/api/identities" 20 vs "github.com/hyperledger/fabric/core/handlers/validation/api/state" 21 "github.com/hyperledger/fabric/core/ledger" 22 "github.com/hyperledger/fabric/msp" 23 "github.com/hyperledger/fabric/protoutil" 24 "github.com/pkg/errors" 25 ) 26 27 //go:generate mockery -dir . -name Mapper -case underscore -output mocks/ 28 29 // Mapper local interface use to generate mock for foreign interface. 30 type Mapper interface { 31 vp.Mapper 32 } 33 34 //go:generate mockery -dir . -name PluginFactory -case underscore -output mocks/ 35 36 // PluginFactory local interface used to generate mock for foreign interface. 37 type PluginFactory interface { 38 validation.PluginFactory 39 } 40 41 //go:generate mockery -dir . -name Plugin -case underscore -output mocks/ 42 43 // Plugin local interface used to generate mock for foreign interface. 44 type Plugin interface { 45 validation.Plugin 46 } 47 48 //go:generate mockery -dir . -name QueryExecutorCreator -case underscore -output mocks/ 49 50 // QueryExecutorCreator creates new query executors 51 type QueryExecutorCreator interface { 52 NewQueryExecutor() (ledger.QueryExecutor, error) 53 } 54 55 // Context defines information about a transaction 56 // that is being validated 57 type Context struct { 58 Seq int 59 Envelope []byte 60 TxID string 61 Channel string 62 VSCCName string 63 Policy []byte 64 Namespace string 65 Block *common.Block 66 } 67 68 // String returns a string representation of this Context 69 func (c Context) String() string { 70 return fmt.Sprintf("Tx %s, seq %d out of %d in block %d for channel %s with validation plugin %s", c.TxID, c.Seq, len(c.Block.Data.Data), c.Block.Header.Number, c.Channel, c.VSCCName) 71 } 72 73 // PluginValidator values transactions with validation plugins 74 type PluginValidator struct { 75 sync.Mutex 76 pluginChannelMapping map[vp.Name]*pluginsByChannel 77 vp.Mapper 78 QueryExecutorCreator 79 msp.IdentityDeserializer 80 capabilities vc.Capabilities 81 } 82 83 //go:generate mockery -dir . -name Capabilities -case underscore -output mocks/ 84 85 // Capabilities local interface used to generate mock for foreign interface. 86 type Capabilities interface { 87 vc.Capabilities 88 } 89 90 //go:generate mockery -dir . -name IdentityDeserializer -case underscore -output mocks/ 91 92 // IdentityDeserializer local interface used to generate mock for foreign interface. 93 type IdentityDeserializer interface { 94 msp.IdentityDeserializer 95 } 96 97 // NewPluginValidator creates a new PluginValidator 98 func NewPluginValidator(pm vp.Mapper, qec QueryExecutorCreator, deserializer msp.IdentityDeserializer, capabilities vc.Capabilities) *PluginValidator { 99 return &PluginValidator{ 100 capabilities: capabilities, 101 pluginChannelMapping: make(map[vp.Name]*pluginsByChannel), 102 Mapper: pm, 103 QueryExecutorCreator: qec, 104 IdentityDeserializer: deserializer, 105 } 106 } 107 108 func (pv *PluginValidator) ValidateWithPlugin(ctx *Context) error { 109 plugin, err := pv.getOrCreatePlugin(ctx) 110 if err != nil { 111 return &validation.ExecutionFailureError{ 112 Reason: fmt.Sprintf("plugin with name %s couldn't be used: %v", ctx.VSCCName, err), 113 } 114 } 115 err = plugin.Validate(ctx.Block, ctx.Namespace, ctx.Seq, 0, vp.SerializedPolicy(ctx.Policy)) 116 validityStatus := "valid" 117 if err != nil { 118 validityStatus = fmt.Sprintf("invalid: %v", err) 119 } 120 logger.Debug("Transaction", ctx.TxID, "appears to be", validityStatus) 121 return err 122 } 123 124 func (pv *PluginValidator) getOrCreatePlugin(ctx *Context) (validation.Plugin, error) { 125 pluginFactory := pv.FactoryByName(vp.Name(ctx.VSCCName)) 126 if pluginFactory == nil { 127 return nil, errors.Errorf("plugin with name %s wasn't found", ctx.VSCCName) 128 } 129 130 pluginsByChannel := pv.getOrCreatePluginChannelMapping(vp.Name(ctx.VSCCName), pluginFactory) 131 return pluginsByChannel.createPluginIfAbsent(ctx.Channel) 132 133 } 134 135 func (pv *PluginValidator) getOrCreatePluginChannelMapping(plugin vp.Name, pf validation.PluginFactory) *pluginsByChannel { 136 pv.Lock() 137 defer pv.Unlock() 138 endorserChannelMapping, exists := pv.pluginChannelMapping[vp.Name(plugin)] 139 if !exists { 140 endorserChannelMapping = &pluginsByChannel{ 141 pluginFactory: pf, 142 channels2Plugins: make(map[string]validation.Plugin), 143 pv: pv, 144 } 145 pv.pluginChannelMapping[vp.Name(plugin)] = endorserChannelMapping 146 } 147 return endorserChannelMapping 148 } 149 150 type pluginsByChannel struct { 151 sync.RWMutex 152 pluginFactory validation.PluginFactory 153 channels2Plugins map[string]validation.Plugin 154 pv *PluginValidator 155 } 156 157 func (pbc *pluginsByChannel) createPluginIfAbsent(channel string) (validation.Plugin, error) { 158 pbc.RLock() 159 plugin, exists := pbc.channels2Plugins[channel] 160 pbc.RUnlock() 161 if exists { 162 return plugin, nil 163 } 164 165 pbc.Lock() 166 defer pbc.Unlock() 167 plugin, exists = pbc.channels2Plugins[channel] 168 if exists { 169 return plugin, nil 170 } 171 172 pluginInstance := pbc.pluginFactory.New() 173 plugin, err := pbc.initPlugin(pluginInstance, channel) 174 if err != nil { 175 return nil, err 176 } 177 pbc.channels2Plugins[channel] = plugin 178 return plugin, nil 179 } 180 181 func (pbc *pluginsByChannel) initPlugin(plugin validation.Plugin, channel string) (validation.Plugin, error) { 182 pe := &PolicyEvaluator{IdentityDeserializer: pbc.pv.IdentityDeserializer} 183 sf := &StateFetcherImpl{QueryExecutorCreator: pbc.pv} 184 if err := plugin.Init(pe, sf, pbc.pv.capabilities, &legacyCollectionInfoProvider{}); err != nil { 185 return nil, errors.Wrap(err, "failed initializing plugin") 186 } 187 return plugin, nil 188 } 189 190 // legacyCollectionInfoProvider implements a provider for collection 191 // information for the legacy lifecycle. It will never be called but 192 // it is necessary to have this dependency passed at init time to the 193 // default plugin 194 type legacyCollectionInfoProvider struct { 195 } 196 197 func (*legacyCollectionInfoProvider) CollectionValidationInfo(chaincodeName, collectionName string, state vs.State) ([]byte, error, error) { 198 panic("programming error") 199 } 200 201 type PolicyEvaluator struct { 202 msp.IdentityDeserializer 203 } 204 205 // Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy 206 func (id *PolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*protoutil.SignedData) error { 207 pp := cauthdsl.NewPolicyProvider(id.IdentityDeserializer) 208 policy, _, err := pp.NewPolicy(policyBytes) 209 if err != nil { 210 return err 211 } 212 return policy.EvaluateSignedData(signatureSet) 213 } 214 215 // DeserializeIdentity unmarshals the given identity to msp.Identity 216 func (id *PolicyEvaluator) DeserializeIdentity(serializedIdentity []byte) (vi.Identity, error) { 217 mspIdentity, err := id.IdentityDeserializer.DeserializeIdentity(serializedIdentity) 218 if err != nil { 219 return nil, err 220 } 221 return &identity{Identity: mspIdentity}, nil 222 } 223 224 type identity struct { 225 msp.Identity 226 } 227 228 func (i *identity) GetIdentityIdentifier() *vi.IdentityIdentifier { 229 identifier := i.Identity.GetIdentifier() 230 return &vi.IdentityIdentifier{ 231 Id: identifier.Id, 232 Mspid: identifier.Mspid, 233 } 234 } 235 236 type StateFetcherImpl struct { 237 QueryExecutorCreator 238 } 239 240 func (sf *StateFetcherImpl) FetchState() (vs.State, error) { 241 qe, err := sf.NewQueryExecutor() 242 if err != nil { 243 return nil, err 244 } 245 return &StateImpl{qe}, nil 246 } 247 248 type StateImpl struct { 249 ledger.QueryExecutor 250 } 251 252 func (s *StateImpl) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (vs.ResultsIterator, error) { 253 it, err := s.QueryExecutor.GetStateRangeScanIterator(namespace, startKey, endKey) 254 if err != nil { 255 return nil, err 256 } 257 return &ResultsIteratorImpl{ResultsIterator: it}, nil 258 } 259 260 type ResultsIteratorImpl struct { 261 ledger2.ResultsIterator 262 } 263 264 func (it *ResultsIteratorImpl) Next() (vs.QueryResult, error) { 265 return it.ResultsIterator.Next() 266 }