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  }