github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/committer/txvalidator/v14/plugin_validator.go (about)

     1  /*
     2  Copyright hechain. 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/hechain20/hechain/common/cauthdsl"
    14  	ledger2 "github.com/hechain20/hechain/common/ledger"
    15  	vp "github.com/hechain20/hechain/core/committer/txvalidator/plugin"
    16  	validation "github.com/hechain20/hechain/core/handlers/validation/api"
    17  	vc "github.com/hechain20/hechain/core/handlers/validation/api/capabilities"
    18  	vi "github.com/hechain20/hechain/core/handlers/validation/api/identities"
    19  	vs "github.com/hechain20/hechain/core/handlers/validation/api/state"
    20  	"github.com/hechain20/hechain/core/ledger"
    21  	"github.com/hechain20/hechain/msp"
    22  	"github.com/hechain20/hechain/protoutil"
    23  	"github.com/hyperledger/fabric-protos-go/common"
    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  func (pv *PluginValidator) getOrCreatePluginChannelMapping(plugin vp.Name, pf validation.PluginFactory) *pluginsByChannel {
   135  	pv.Lock()
   136  	defer pv.Unlock()
   137  	endorserChannelMapping, exists := pv.pluginChannelMapping[vp.Name(plugin)]
   138  	if !exists {
   139  		endorserChannelMapping = &pluginsByChannel{
   140  			pluginFactory:    pf,
   141  			channels2Plugins: make(map[string]validation.Plugin),
   142  			pv:               pv,
   143  		}
   144  		pv.pluginChannelMapping[vp.Name(plugin)] = endorserChannelMapping
   145  	}
   146  	return endorserChannelMapping
   147  }
   148  
   149  type pluginsByChannel struct {
   150  	sync.RWMutex
   151  	pluginFactory    validation.PluginFactory
   152  	channels2Plugins map[string]validation.Plugin
   153  	pv               *PluginValidator
   154  }
   155  
   156  func (pbc *pluginsByChannel) createPluginIfAbsent(channel string) (validation.Plugin, error) {
   157  	pbc.RLock()
   158  	plugin, exists := pbc.channels2Plugins[channel]
   159  	pbc.RUnlock()
   160  	if exists {
   161  		return plugin, nil
   162  	}
   163  
   164  	pbc.Lock()
   165  	defer pbc.Unlock()
   166  	plugin, exists = pbc.channels2Plugins[channel]
   167  	if exists {
   168  		return plugin, nil
   169  	}
   170  
   171  	pluginInstance := pbc.pluginFactory.New()
   172  	plugin, err := pbc.initPlugin(pluginInstance, channel)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	pbc.channels2Plugins[channel] = plugin
   177  	return plugin, nil
   178  }
   179  
   180  func (pbc *pluginsByChannel) initPlugin(plugin validation.Plugin, channel string) (validation.Plugin, error) {
   181  	pe := &PolicyEvaluator{IdentityDeserializer: pbc.pv.IdentityDeserializer}
   182  	sf := &StateFetcherImpl{QueryExecutorCreator: pbc.pv}
   183  	if err := plugin.Init(pe, sf, pbc.pv.capabilities, &legacyCollectionInfoProvider{}); err != nil {
   184  		return nil, errors.Wrap(err, "failed initializing plugin")
   185  	}
   186  	return plugin, nil
   187  }
   188  
   189  // legacyCollectionInfoProvider implements a provider for collection
   190  // information for the legacy lifecycle. It will never be called but
   191  // it is necessary to have this dependency passed at init time to the
   192  // default plugin
   193  type legacyCollectionInfoProvider struct{}
   194  
   195  func (*legacyCollectionInfoProvider) CollectionValidationInfo(chaincodeName, collectionName string, state vs.State) ([]byte, error, error) {
   196  	panic("programming error")
   197  }
   198  
   199  type PolicyEvaluator struct {
   200  	msp.IdentityDeserializer
   201  }
   202  
   203  // Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
   204  func (id *PolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*protoutil.SignedData) error {
   205  	pp := cauthdsl.NewPolicyProvider(id.IdentityDeserializer)
   206  	policy, _, err := pp.NewPolicy(policyBytes)
   207  	if err != nil {
   208  		return err
   209  	}
   210  	return policy.EvaluateSignedData(signatureSet)
   211  }
   212  
   213  // DeserializeIdentity unmarshals the given identity to msp.Identity
   214  func (id *PolicyEvaluator) DeserializeIdentity(serializedIdentity []byte) (vi.Identity, error) {
   215  	mspIdentity, err := id.IdentityDeserializer.DeserializeIdentity(serializedIdentity)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	return &identity{Identity: mspIdentity}, nil
   220  }
   221  
   222  type identity struct {
   223  	msp.Identity
   224  }
   225  
   226  func (i *identity) GetIdentityIdentifier() *vi.IdentityIdentifier {
   227  	identifier := i.Identity.GetIdentifier()
   228  	return &vi.IdentityIdentifier{
   229  		Id:    identifier.Id,
   230  		Mspid: identifier.Mspid,
   231  	}
   232  }
   233  
   234  type StateFetcherImpl struct {
   235  	QueryExecutorCreator
   236  }
   237  
   238  func (sf *StateFetcherImpl) FetchState() (vs.State, error) {
   239  	qe, err := sf.NewQueryExecutor()
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  	return &StateImpl{qe}, nil
   244  }
   245  
   246  type StateImpl struct {
   247  	ledger.QueryExecutor
   248  }
   249  
   250  func (s *StateImpl) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (vs.ResultsIterator, error) {
   251  	it, err := s.QueryExecutor.GetStateRangeScanIterator(namespace, startKey, endKey)
   252  	if err != nil {
   253  		return nil, err
   254  	}
   255  	return &ResultsIteratorImpl{ResultsIterator: it}, nil
   256  }
   257  
   258  type ResultsIteratorImpl struct {
   259  	ledger2.ResultsIterator
   260  }
   261  
   262  func (it *ResultsIteratorImpl) Next() (vs.QueryResult, error) {
   263  	return it.ResultsIterator.Next()
   264  }